강의/Unity

유니티 비동기 프로그래밍 - 1. Coroutine 이해

개발의 피 2024. 7. 28. 10:13

1.  개요

코루틴의 개념, 주요 키워드 (코루틴 코드 작성에 필요한 기본 지식)

 

2. Unity Coroutine 개요

1) 정의

- 기능 : 메서드를 여러 번에 걸쳐 나누어 실행할 수 있는 기능

- 동작 방식 : 메서드를 실행하다가 그 상태로 그대로 일시 중단하고, 다른 메서드를 처리한 후, 다시 돌아와서 작업을 이어서 재개

 

2) 동작 예시 

A 작업 처리하다가 중단 → B 작업 처리하다가 중단 → 다시 A 작업 이어서 처리하다가 중단

→ C 작업 처리하다가 중단 → B 작업 마무리 → A 작업 처리하다가 중단

→ C 작업 마무리 → A 작업 마무리 

 

여러 작업을 중단과 재개를 반복하여 처리 !

 

3) 코루틴의 단점

- 멀티스레드가 아님 

- 스레드 : 물리적으로 동시에 실행

- 코루틴 : 유니티 메인스레드에서 순차적으로 실행되지만, 여러 코루틴 간의 중단과 재개가 매우 빠른 속도로 진행되어 논리적으로 동시에 실행되는 것처럼 보이는 상태 

cf. 물리적으로 동시에 실행되는 기능이 필요하면, Thread나 Task, Unity의 Job System을 이용

 

-> 잡 시스템... 처음 들어봐서 검색해봤다 나중에 필요하면 공부하기

(대충 유니티에서 제공하는 멀티스레딩 프레임워크로, 게임 성능을 개선할 수 있다고 한다)


https://docs.unity3d.com/kr/2018.4/Manual/JobSystem.html

 

C# 잡 시스템 - Unity 매뉴얼

Unity C# 잡 시스템(Job System)을 사용해 Unity 엔진과 상호작용하는 간단하고 안전한 멀티스레드 코드를 작성하여 게임 성능을 개선할 수 있습니다.

docs.unity3d.com

 

또 메인 스레드가 있으면, 다른 스레드에는 어떤 스레드가 있는지 궁금했다 

https://www.jacksondunstan.com/articles/3930

- 메인 스레드 : 유니티의 기본 작업(게임 로직, 물리 엔진, UI 등)을 처리

- 워커 스레드 : 백그라운드 작업 및 비동기 작업을 처리

이렇게 크게 스레드는 두 종류로 구분하는 것 같았고, 워커 스레드에 물리 스레드, 렌더 스레드, 오디오 스레드 ... 등의 스레드 등이 포함되는 걸로 보였다 

 

- 코루틴 메소드는 별도의 리턴을 받을 수 없음 -> 비동기로 기다렸다가 결과를 받아서 사용하려면 , 콜백이나 레퍼런스 파라미터 등 다른 수단을 사용해야 함

- 또 yield return을 사용할 때마다 인스턴스를 만들어야 하는 제약등으로 인해 가비지가 적지 않아서, 전체적인 성능 향상에는 그리 효율적이지 않을수도 

 

4) 코루틴을 이용한 비동기 프로그래밍 활용 사례

- 일정 시간 뒤에 실행

- 조건에 맞을 때까지 기다렸다가 실행

- 비디오, 오디오, 오디오, 파일 등을 다운로드 한 뒤에 실행

- 비동기로 씬 전환을 기다렸다가 실행

- 일정 주기로 반복해서 실행 

 

5) 코드 비교 (순차처리)

일반 코드보다 코루틴 메소드로 순차처리하는 코드가 더 짧고, 직관적

- 일반 메서드 

private int order;
private float timer;

private void Update()
{
    timer += Time.deltaTime;
    
    if (order == 1)
    {
        if (timer >= 1f)
        {
            order++;
            timer = 0f;
            Debug.Log("화이탱");
        }
    }
}

- 코루틴 메서드 

private void Start()
{
    StartCoroutine(Process());
}

private IEnumerator Process()
{
    yield return new WaitForSeconds(1f);
    Debug.Log("화이팅");
}

 

3. 코루틴의 주요 키워드

1) IEnumerator, IEnumerable : C#의 인터페이스

- IEnumerator : 여러 차례에 걸쳐 메서드의 실행을 일시 중단하고 값을 반환할 수 있음

- IEnumerable : 클래스 인스턴스를 반복기 등에서 사용할 때, IEnumerabor를 자동으로 제공해줘서 foreach 등의 반복기에서 손쉽게 순회할 수 있도록 도와주는 인터페이스 

 

2) yield break, yield return

- yield : 보통 IEnumerator를 반환값으로 사용하는 메서드 내에서만 사용되며, 양보라는 사전적 의미처럼 이 키워드가 실행되는 순간 그 메서드의 실행을 중단하고 메서드를 호출한 지점으로 되돌아가게 됨

 

- yield break : 반복문의 break처럼, 이 메서드의 반복을 완전히 중단하게 됨 

-  yield return : IEnumerator를 돌려주면서 일시 중단

 

4. 코루틴의 시작과 종료

코루틴을 시작하고 종료하는 방법

 

1)

코루틴은 IEnumerator를 반환 값으로 사용하는 메서드를 구현하고, 

이 메서드를 DelayedCallManager에 넘겨서 실행하는 식으로 사용

그러면 DelayedCallManager는 IEnumerator 메서드를 순차적으로 실행하면서 yield를 통해 넘어온 값을 기준으로 언제까지 재개해야 하는지 판단하여 메서드를 일시중단하거나 재개해주는 기능 담당

 

유니티에서 DelayedCallManager를 직접 다루지는 않고, 다만 코루틴 메서드를 등록하는 형태로 간접적으로 사용하게 됨

코루틴 메서드를 DelayedCallManager에 등록하려면 StartCoroutine 메소드를 사용해야됨 

 

다시 볼 부분 : StartCoroutine 실행 방법

 

2) 실행한 코루틴 메소드가 종료되는 사항들

 

5. yield에 사용할 수 있는 것들

코루틴  : yield return 뒤에 다시 재개할 수 있는 방식을 지정할 수 있는 인스턴스를 사용할 수 있음 

이 자리에는 yield instruction이나 custom yield instruction, IEnumerator에서 파생된 클래스 등을 사용할 수 있는데, 모든 사용법을 당장 외울 필요는 x 

1) yield return null 

아무런 조건 없이 다음 프레임에 코루틴 메소드를 재개하는 기능

fade in out 이나 매 프레임에 걸쳐 진행해야 하는 기능 등에서 사용

 

2) yield return new WaitForSeconds

매개변수로 들어온 실수 값의 초만큼 시간이 흐른 뒤에 코루틴 메소드를 재개

유의 : 정확히 해당 시간이 흘렀을 때 실행 x, 해당 시간이 흐른 뒤에 재개할 수 있는 가장 빠른 프레임에 재개 o

일정 시간마다 기능을 실행하거나, 일정 시간 동안 기다렸다가 실행하고 싶은 기능을 처리하고 싶을 때 사용

 

 

3) yield return new WaitForSecondsRealtime

2번과 달리 타임 스케일에 영향받지 않음 

그 외의 기능은 2번과 같음 

 

4) yield return new WaitForFixedUpdate

다음 FixedUpdate가 끝난 직후에 재개

물리 처리가 끝나고 난 뒤에 하고 싶은 기능을 실행할 때 사용

 

5) yield return new WaitForEndOfFrame

렌더링이 완료된 직후에 재개되는 기능

렌더링 처리가 끝나고 난 뒤에 하고 싶은 기능을 실행할 때 사용

 

6) yield return StartCoroutine(Coroutine)

다른 코루틴을 yield return 옆에 사용하면 대기할 수 있음

옆에 사용한 코루틴이 종료된 직후에 재개됨

여러 코루틴을 복합적으로 사용하여 논리적인 흐름을 정리할 때 사용 

코루틴 메소드를 yield return으로 바로 대기할 수도 있고, start coroutine으로 감싸 별도로 실행한 코루틴 메소드를 대기할 수도 있음

바로 대기할 경우 별개의 코루틴 메소드가 등록되지 않고, 내장된 코드인 것처럼 하나의 코루틴에서 실행됨 

 

7) yield return AsyncOperation

유니티 맵 리퀘스트 등 async operation이 종료된 후에 재개

이미지 등의 파일 다운로드가 완료된 뒤에 이어서 실행하고 싶을 때 사용

 

8) yield return new WaitUntil(Func<bool>)

매개변수로 넘겨준 funcion의 결과 값이 true가 나올 때까지 기다렸다가 재개 

사용자의 입력이나 특정 지점에 들어서거나 하는 등의 이벤트와 함께 사용

 

9) yield return new WaitWhile(Func) 

waituntil과 반대로 매개변수로 넘겨준 funcion의 값이 false가 나올 때까지 기다렸다가 재개 

보통 8과 9 중에 취향에 맞는 걸 사용하는 편 

 

* 모든 사용법을 당장 알 필요는 없음!