Unity 코루틴 소소한 정리

2022년 06월 21일
제작기간 2022년 06월 21일
태그 Unity

동기 & 비동기

  • 동기(Synchronous)는 요청 후, 결과를 반환받은 후 작업 진행함.
  • 비동기(Asynchronous)는 요청 후, 결과를 기다리지 않고 작업 진행함.

코루틴

  • Coroutine은 동시 실행 설계 패턴임.
  • 코루틴은 상호협력적이며, 서로가 서로를 호출할 수 있고, 서로가 서로의 서브 루틴이 될 수 있음(대칭적임).
  • 코루틴은 발동될 때, 마지막 중단 지점에서 작업을 재개함.

C

  • yield return은 각 element를 하나씩 리턴할 때 사용할 수 있음.
  • yield break을 통해 iteration을 종료할 수 있음.
  • [IEnumerator]는 Generic Collection에 대해 간단한 iteration을 지원함.
using System.Collections;

var counter = Counter();

while (counter.MoveNext())
{
    Console.WriteLine($"Current: [{counter.Current ?? "NULL"}]");
}

IEnumerator Counter()
{
    var count = 0;
    for (int i = 0; i < 5; i++)
    {
        count++;
        Console.WriteLine($"Update Counter: {count}");
        yield return count;
    }
}

// ouputs
// Update Counter: 1
// Current: [1]
// Update Counter: 2
// Current: [2]
// ...
// Update Counter: 5
// Current: [5]

Unity Coroutine

  • 코루틴을 통해 프레임에 국한받지 않고 작업을 진행할 수 있음.
  • 시간의 흐름에 따른 이벤트의 시퀀스, 절차상의 애니메이션 실행에 용이.
  • 코루틴은 메인 스레드 위에서 실행됨. (멀티 스레딩이 아님.)
  • yield return: 코루틴 실행을 정지하고 제어권을 Unity에게 넘김.
  • 성능
    • C# 컴파일러가 코루틴을 지원하는 class Instance를 자동 생성함 -> Unity의 main loop 도중, DelayedCallManager가 이 오브젝트를 통해 코루틴 상태를 트랙킹함 -> 조건 만족시 오브젝트 호출
    • 로컬 변수가 힙에 할당된 상태로 남아있음: Coroutine의 local 변수가 yield 호출이 진행되는 동안 유지되어야 함 -> 생성된 class로 로컬 변수를 옮김
    • 코루틴 메모리 사용량 = 고정된 오버헤드 + 로컬 변수 용량
  • 이점
    • Update에서의 작업을 분리할 수 있어 가독성을 크게 개선할 수 있음.
    • Update는 가변적인 간격을 가지고 있는데 코루틴을 사용하면 원하는 시간 딜레이를 프레임 속도를 고려하지 않고 줄 수 있음.
public static IEnumerator LoadScene(string sceneName, Action<float> progressCallback = null, Action doneCallback = null)
{
    AsyncOperation op = SceneManager.LoadSceneAsync(sceneName);
    op.allowSceneActivation = false;
    while (!op.isDone)
    {
        // 다음 프레임까지 기다림
        yield return null;
        progressCallback?.Invoke(op.progress);

        // allowSceneActivation이 false이면, Unity는 씬 로딩 진행도를 0.9에서 멈추고 isDone을 false로 유지함
        if (op.progress >= 0.9f)
            break;
    }
    doneCallback?.Invoke();
    op.allowSceneActivation = true;
}

C# Job System

  • 스레드를 직접 생성하지 않고 Job을 만들어 멀티스레딩을 할 수 있게 제공되는 시스템.
    • 잡 대기열의 잡을, 워커 스레드가 가져와서 실행함.
    • 코어당 하나의 워커 스레드: CPU core보다 많은 스레드를 만드는 것을 방지(context switching 방지)하여 CPU 경쟁을 피할 수 있음.
  • 안전한 멀티스레드 코드를 작성할 수 있음.
  • 유니티에서 프레임 속도를 개선할 수 있으며, 모바일 배터리 소모량을 감소할 수 있음.
  • Unity’s native job system과 통합하여 사용할 수 있음.