Coroutine
: Unity 엔진이 제공하는 실행을 일시 중단하고, 이후 특정 시점에 이어서 실행할 수 있는 함수
- C#의 반복자 (
IEnumerator)를 유니티 엔진이 활용하여 만든 협력적 멀티태스킹 (Cooperative Multitasking) 방식
- C# 컴파일러가 IEnumerator 상태 머신으로 변환
yield return 을 만나면 함수가 완전히 종료되는 것이 아닌 그 지점에서 실행을 일시 정지하고 제어권을 자신이 호출한 쪽으로 넘긴다
- 유니티 PlayerLoop가
MoveNext() 를 호출하면, 멈췄던 바로 그 다음 줄부터 코드를 다시 이어서 실행
- 비동기 처럼 보이지만 멀티 스레드 환경이 아닌, 메인 스레드에서 실행
- 여러 코루틴 코드가 유니티 엔진의 스케줄링하에 프레임 단위로 쪼개져 실행
- MonoBehaviour 객체에 종속
- MonoBehaviour 컴포넌트가 비활성화 → 코루틴 중단 없음
- GameObject가 비활성화되거나 파괴 → 코루틴 중단
- try-catch 블록 내부에서 yield return 사용 불가
- 직접적인 반환 값 사용 불가
- 종료
StopCoroutine
yield break : 종료
- 사용처
- 단순한 시각적 효과, 프레임 단위의 애니메이션 제어 등 유니티 라이프사이클과 결합된 프론트엔드 연산을 할 때
- yield return 종류
null : 다음 프레임의 Update 이후 재개
new WaitForSeconds(1f) : 1초 후 다음 갱신 시점에 재개
new WaitForFixedUpdate() : 다음 프레임의 FixedUpdate 이후 재개
new WaitForEndOfFrame() : 현재 프레임의 렌더링 이후 재개
new WaitUntil(() ⇒ isComplete) : 조건이 만족되면 재개
new WaitWhile(() => isLoading) : 조건이 만족되는 동안 중단
async/await
: 비동기 작업이 완료될 때까지 기다렸다가 이후 코드를 이어서 실행하는 C# 네이티브 기능
- async : 이 메소드 안에서 await를 사용할 수 있도록 만드는 키워드
- C# 컴파일러가 코드를 상태 머신으로 변환 (
IAsyncStateMachine )
- await : Task가 완료될 때까지 현재 메소드 실행을 일시 중단하는 키워드
- try-catch 사용 가능
CancellationToken 으로 취소
- 사용처
- 네트워크 통신, 파일 I/O, 무거운 데이터 로딩 등 시스템 외부와 통신하거나 순수한 비즈니스 로직을 처리할 때
Task
: 비동기 작업의 상태와 완료 여부를 표현하는 객체
- 생성됨 or 실행중 or 완료됨 or 실패함 or 취소됨
- Task ≠ Thread
- 주요 멤버
Task.CompletedTask
Task.FromResult<T>()
Task.Run()
- CPU를 많이 사용하는 작업을 Worker Thread에서 실행
- Thread를 생성하는 것이 아닌 ThreadPool에 작업 등록
- Main Thread → ThreadPool Worker Thread → Main Thread 복귀
Task.WhenAll()
- 모든 Task가 완료될 때까지 대기
- 독립적인 작업을 동시에 진행할 때 사용
Task.WhenAny()
- 값 반환
Task<T> 를 통해 반환 값 사용 가능
- async Task는 명시적인 return 문이 없어도 컴파일러가 알아서 완료된 Task 반환
- async 키워드가 없는 경우 직접 반환 필수
- 주의 사항
async void 지양 ⇒ async Task 로 사용
- 게임 오브젝트가 파괴되어도 자동 취소되지 않는다
CancellationToken 을 통해 명시적으로 취소 가능
- Worker Thread에서 Unity API 접근 불가
- async/await는 상태 머신과 Task 객체를 생성하며, 실행 과정에서 추가적인 메모리 할당이 발생할 수 있다
- C# 컴파일러가 만드는 상태머신은 구조체
- 서드파티 라이브러리
UniTask 를 사용하여 GC 할당 감소 가능
코루틴 vs Async
| 코루틴 | Async |
|---|
| 정의 | Unity 엔진이 제공하는 실행 흐름 제어 기능 | C#이 제공하는 비동기 프로그래밍 기능 |
| 멀티 스레드 | X | Task.Run |
| 반환 값 | 직접 반환 불가 | Task |
| 예외 처리 | 제한적 | try-catch 가능 |
| 생명 주기 | MonoBehaviour에 종속 | 독립적 |
| 취소 | StopCoroutine | CancellationToken |
| 사용처 | Unity의 프레임 흐름이나 게임 연출과 밀접한 작업 | 외부 작업의 완료를 기다리는 작업 |
Coroutine을 선호하는 경우
- Ex
- 프레임 내부에서도 제어가 필요할 때
- 연출 및 애니메이션
- 시간 흐름을 표현하는 로직
- 게임 오브젝트 생명주기에 종속된 로직
- Why
- MonoBehaviour
- Transform, UI, 물리 연산 등 엔진 API는 메인스레드에서만 접근 가능
Async를 선호하는 경우
- Ex
- 네트워크 통신
- I/O
- 무거운 CPU 연산
- 메인 스레드에서 처리하면 프레임 드랍이 생기는 로직
- Why
- 외부 라이브러리와 연동
- 반환값이 필요할 때
- 예외 처리
- 여러 작업 동시 처리