부트캠프/Unity [ 스파르타 ]

[스파르타 ][TIL] 유니티 스파르타 7기 58일차 - UniTask

맏난거 2025. 5. 1. 21:00

🔷 1. 왜 UniTask를 쓰는가?

Unity는 기본적으로 Coroutine 기반의 비동기 처리를 제공하지만, 다음과 같은 단점이 있습니다:

Coroutine의 단점UniTask의 장점
반환값을 가질 수 없음 UniTask<T>로 반환값을 가짐
예외처리가 번거로움 (try-catch 안됨) try-catch로 자연스럽게 예외처리 가능
중첩 호출 시 복잡하고 유지보수 어려움 await로 직관적인 비동기 흐름 가능
GC 발생 없음(좋음)이지만 타입 제약 있음 UniTask는 GC 거의 없음 + 제네릭 지원

🔷 2. UniTask 기본 사용법

✅ 단순 지연

using Cysharp.Threading.Tasks;

public async UniTaskVoid DelayExample()
{
    Debug.Log("Start");
    await UniTask.Delay(1000); // 1초 대기
    Debug.Log("End");
}

✅ 반환값 있는 경우

public async UniTask<int> GetData()
{
    await UniTask.Delay(500);
    return 42;
}

public async UniTaskVoid UseData()
{
    int result = await GetData();
    Debug.Log(result); // 42
}

🔷 3. UniTask와 Coroutine 비교

항목CoroutineUniTask
반환값 지원 ❌ 불가능 ✅ UniTask<T> 사용 가능
예외 처리 ❌ try-catch 불가능 ✅ try-catch 사용 가능
GC 발생량 ✅ 적음 ✅ 매우 적음 (Zero Allocation 구조체)
Unity 생명주기 통합 ❌ 직접 관리 필요 ✅ OnDestroy와 연동 가능

🔷 4. 취소 (Cancellation)

CancellationTokenSource cts = new();
await UniTask.Delay(5000, cancellationToken: cts.Token);
// 중간에 cts.Cancel() 호출 시 취소됨

🔷 5. 사용 시 주의사항

  • 메인 스레드에서만 작동하는 Unity API 사용 시 await 뒤에는 반드시 메인스레드로 돌아와야 함
    → UniTask.SwitchToMainThread() 또는 PlayerLoop 기반 호출 사용
  • UniTaskVoid는 fire-and-forget용으로, 예외가 잡히지 않으므로 최소한으로만 사용

🔷 6. Unity 관련 예시

public async UniTask WaitForButton(Button btn)
{
    await btn.OnClickAsync(); // UniTask가 지원하는 확장 메서드
    Debug.Log("Button Clicked!");
}

✳️ UniTask는 언제 쓰면 좋을까?

  • 복잡한 비동기 흐름 (Coroutine으로는 너무 꼬임)
  • 반환값이나 예외 처리 필요
  • 네트워크 통신, 리소스 로딩, 애니메이션 처리 등