[TIL] 유니티 Coroutine VS Async/Await

Dreamer·2025년 1월 8일

1. 오늘 주제

유니티에서 사용하는 비동기에 대해 알아보자.

유니티에서는 비동기 수행하는데 있어서 크게 2가지로 나뉜다.
하나는 Coroutine, 하나는 Async/Await 이다.

Coroutine은 유니티의 메인 스레드에서 동작하며, yield return으로 비동기 흐름을 표현는 것으로 실질적으로 비동기 형태로 실행되진 않는다.

Async/Await은 C# 언어 자체 기능으로, 실제 비동기 작업(다른 스레드) 또는 비동기 I/O를 처리가 가능하다.

크게 두가지의 차이점으로는
Coroutine은 유니티 프레임워크에 종속적이며 Update 루프에서 스케줄링하게 된다.
Async/Await는 .NET/C#의 표준 비동기 방식으로, CPU 바운드/IO 바운드 작업 모두 처리 가능.

하지만 유니티에서는 Async/Await 을 사용하게 되면 Unity API 대부분은 메인 스레드에서만 안전하게 호출 가능. Async 스레드에서 UI 조작 시 문제가 생길 수 있으므로, 적절한 스레드 전환이 필요하다.

예를 들어

  • 유니티 게임 오브젝트의 라이프사이클이나, 플레이어 루프의 각 이벤트 타이밍을 감지할 수 없는 문제
  • async Task 메서드를 호출할 때마다 메모리 할당이 발생.
  • AsyncOperation들을 await 할수 없음.

같은 문제가 있다.

그런데 Unity6로 넘어가면서 Awaitable 이라는 녀석이 생겼는데 Awaitable 타입은 유니티에서 Task를 대체하여 비동기 작업을 표현하는 타입으로, 유니티가 추적할 수 있는 타입으로 Awaitable은 Task와 비교하여 유니티 개발 환경에 최적화되어 설계되어 나오게 된 것이다.

이로써 유니티에서 온전히 async/await을 사용 할 수 있게 되었다.

예시 코드

public async Awaitable GetAssetAsync(string assetName)
{
    var assetLoadOperation = Addressables.LoadAssetAsync(assetName);
    await assetLoadOperation.Task;
    return loadedAsset = assetLoadOperation.Result;
}


public async void Start()
{
    var loadedAsset = await GetAssetRoutine("boat");

    await DoSomethingAsync1(loadedAsset);
    await DoSomethingAsync2(loadedAsset);
    await DoSomethingAsync3(loadedAsset);
}

(콜백 지옥 안녕..)

아무래도 Awatiable 풀링해서 사용하다보니 상황에 따라 다른 Awatiable 을 사용해야하지만 동일한 Awatiable 인스턴스를 사용하는 경우가 있나보다.
자세한 내용은 참조 페이지를 보면 되겠다.

(참조: https://www.unitysquare.co.kr/growwith/unityblog/webinarView?id=566)

얼른 Unity6로 넘어가야지..

profile
새로운 시작

0개의 댓글