2024.11.18 - [분류 전체보기] - 유니티 - 비동기 프로그래밍에 대해 알아보자. #3 (UniTask)
오늘은 awaitable을 정리하는 시간을 가지고자 합니다.
Awaitable
Awaitable 타입은 유니티에서 Task를 대체하여 비동기 작업을 표현하는 타입으로,
유니티가 추적할 수 있는 타입입니다.
Task와 비교하여 유니티 개발 환경에 최적화되어 설계되었다고 합니다.
특징
내부 풀링 시스템으로 메모리 할당 최소화
=> async 메서드를 실행할 때마다 Task 타입을 위한 메모리 할당이 발생하는 문제를 해결
=> 동일 인스턴스 중복 await이 불가능하다.
GC 압박감소
주요 메서드
NextFrameAsync(): 다음 프레임 대기
WaitForSecondsAsync(): 시간 대기
EndOfFrameAsync(): 프레임 끝 대기
AwaitableCompletionSource로 수동 완료 처리해야 한다.
UniTask와 Awaitable 비교
UniTask에서 이야기했던 비교 내용을 가져와 정리해 봤습니다.
원문을 읽어보고 싶으신 분이라면 아래 링크에서 awaitable 내용을 찾아보시면 됩니다.
https://github.com/Cysharp/UniTask
정리 :
UniTask와 비교하여
프레임 기반 작업 제한적
PlayerLoopTiming(= Unity의 실행 루프(Update loop) 내의 특정 타이밍 ) 제어 기능 제한
Tracker Window 없음
결론:
UniTask가 Awaitable의 상위 집합이므로,
특별한 제약이 없다면 UniTask 사용이 더 유리함
외부 종속성 회피 필요시 Awaitable 사용
그 외에는 UniTask 권장
Task와 Awaitable 비교
아래 표는 참고 자료 중 유니티 매뉴얼에 들어가면 Task와 awaitable을 비교하는 원본 내용을 보실 수 있습니다.
특징 | Task | Awaitable
----------------------|---------------------------|---------------------------
다중 await | 가능 | 불가능 (풀링으로 인해)
값 반환 | Task<T> 지원 | Awaitable<T> 지원
완료 트리거 | TaskCompletionSource | AwaitableCompletionSource
연속성 실행 | 비동기(ThreadPool 사용) | 동기(즉시 실행)
결론 :
Unity 게임 개발에서는 성능을 위해 Awaitable 사용이 권장되나, 중복 await가 필요한 경우 Task 사용 고려
예시 코드
using UnityEngine;
using System;
public class AwaitableExample : MonoBehaviour
{
// 1. 기본적인 Awaitable 사용
async void BasicExample()
{
// 다음 프레임까지 대기
await Awaitable.NextFrameAsync();
// 지정된 시간만큼 대기
await Awaitable.WaitForSecondsAsync(2.0f);
// EndOfFrame까지 대기
await Awaitable.EndOfFrameAsync();
}
// 2. 값을 반환하는 Awaitable 사용
async void ReturnValueExample()
{
Awaitable<int> calculation = CalculateAsync();
int result = await calculation;
Debug.Log($"계산 결과: {result}");
}
async Awaitable<int> CalculateAsync()
{
await Awaitable.NextFrameAsync();
return 42;
}
// 3. AwaitableCompletionSource 사용
async void CompletionSourceExample()
{
var completionSource = new AwaitableCompletionSource<string>();
// 다른 스레드나 이벤트에서 완료 처리
CompleteAsync(completionSource);
// 결과 대기
string result = await completionSource.Awaitable;
Debug.Log(result);
}
async void CompleteAsync(AwaitableCompletionSource<string> source)
{
await Awaitable.NextFrameAsync();
source.SetResult("완료!");
}
// 4. 취소 토큰 사용
async void CancellationExample()
{
var cancellationToken = this.GetCancellationTokenOnDestroy();
try
{
await Awaitable.WaitForSecondsAsync(5.0f, cancellationToken);
Debug.Log("완료!");
}
catch (OperationCanceledException)
{
Debug.Log("작업이 취소됨");
}
}
// 5. 풀링된 Awaitable 사용 시 주의 사항
async void PoolingWarningExample()
{
// 올바른 사용
await Awaitable.NextFrameAsync();
await Awaitable.NextFrameAsync();
// 잘못된 사용 - 동일 인스턴스 재사용
var awaitable = Awaitable.NextFrameAsync();
await awaitable;
// await awaitable; // 예외 발생!
}
// 6. 연속성 실행 예제
async void ContinuationExample()
{
Debug.Log("시작");
await Awaitable.NextFrameAsync();
Debug.Log("동기적으로 즉시 실행됨");
await Task.Yield();
Debug.Log("비동기적으로 실행됨 (ThreadPool)");
}
// 7. 실제 사용 사례
async void LoadResourceExample()
{
try
{
// 리소스 로딩
var request = Resources.LoadAsync<GameObject>("Prefab");
await request;
if (request.asset != null)
{
var go = Instantiate(request.asset as GameObject);
await Awaitable.WaitForSecondsAsync(1.0f);
Destroy(go);
}
}
catch (Exception e)
{
Debug.LogError($"리소스 로딩 실패: {e.Message}");
}
}
// 8. 여러 Awaitable 조합
async void CombineAwaitablesExample()
{
var task1 = DoSomethingAsync();
var task2 = DoSomethingElseAsync();
await task1;
await task2;
Debug.Log("모든 작업 완료");
}
async Awaitable DoSomethingAsync()
{
await Awaitable.WaitForSecondsAsync(1.0f);
}
async Awaitable DoSomethingElseAsync()
{
await Awaitable.WaitForSecondsAsync(2.0f);
}
}
마무리
오늘은 간단하게 awaitable에 대해 정리해 봤습니다.
awaitable이 뭔지 호기심에서 시작한 건데 참 멀리도 돌아왔네요 ㅋ;
자료를 정리하면서 보니까 비교 부분에서도 설명했지만
큰 이유 없으면 웬만해선 다들 Unitask로 진행하는 것 같습니다.
참고한 자료
https://youtu.be/2fupgczJn9g?si=ip5ppV9wdt0R642D
https://docs.unity3d.com/kr/2023.2/Manual/AwaitSupport.html
Await 지원 - Unity 매뉴얼
Unity 2023.1에서는 C# async 및 await 키워드를 사용하여 간소화된 비동기 프로그래밍 모델을 지원합니다. Unity의 비동기 API는 대부분 다음을 포함하는 async/await 패턴을 지원합니다.
docs.unity3d.com
https://docs.unity3d.com/kr/2023.2/ScriptReference/Awaitable.html
Awaitable - Unity 스크립팅 API
Awaitable type used to expose asynchronous code, as well as an async return type specifically tailored for Unity.
docs.unity3d.com
Unity Square
Unity 6 Awaitable로 깔끔한 비동기 프로그래밍 구현하기
unitysquare.co.kr