동기 & 비동기
- 동기(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로 로컬 변수를 옮김
- 코루틴 메모리 사용량 = 고정된 오버헤드 + 로컬 변수 용량
- C# 컴파일러가 코루틴을 지원하는 class Instance를 자동 생성함 -> Unity의 main loop 도중,
- 이점
- 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과 통합하여 사용할 수 있음.