UniTask에 대해서는 이전 들에서 알아 보았다.
https://note4iffydog.tistory.com/43
이전 글에서도 Unitask 대한 어떤 정의 보다는 왜 나왔고, 어떤 원리로 돌아 가는 지 확인하는 글을 써보았다.
이제 왜 나왔는 지 알아보았으니, 어떻게 쓰는 지 알아 봐야 할 차례다.
사용법은 c# async-await와 같다. 다만, UniTask에서 사용 할수 있는 몇가지 특징들이 있는 데, 거기에 더 집중적으로 파볼 것이다. 간단한 사용법은 gpt나 블로그에 정말 많고, 그보다 실제로 써보았을 때 생기는 의문점들이나, 유용했던 것들을 정리 하는게 더 유용하리라 생각 각한다.
UniTask vs UniTaskVoid
UniTask와 UniTaskVoid가 있다. 왜 다르게 사용 할까. 이름에서 느껴지듯이 UniTask가 조금 더 가볍(?)다. 작업이 가볍냐고 생각하기보다 과정이 가볍다라고 생각하자. UniTaskVoid는 awaitable 완료 기능이 없고,UniTaskScheduler.UnobservedTaskException 에 바로 에러리포트를 날려준다.
다만 awaitable이 아니기에 await가 아닌 경우에만 사용 하고, forget()을 뒤에 넣어주어 에러 메세지를 없애도록 하자.
Cancellation
UniTask의 작업을 메뉴얼로 관리해주고, lifecycle을 커스텀 할수 있게 하는 것은 효율적인 일이다. 이를 위해선 UniTask의 cancellation token에 대해서 이해를 하고 어떻게 사용하는 지 알아야 한다. Cancellation token은 UniTask의 작업을 종료하는 데 쓰이는 요소이다. 중간에 token이 파괴 되면, OperationCanceledException 이 불리게 된다. 물론, 수작업으로 한다면, 말이다. 제대로 Exception관리를 안해주면 UnobservedTaskException이 일어나게 된다.
private void OnDisable()
{
disableCancellation.Cancel();
}
private void OnDestroy()
{
destroyCancellation.Cancel();
destroyCancellation.Dispose();
}
cancellation을 어떻게 메뉴얼하게 처리 할수 있을 까. 이는 UniTask 내부에 TimeOut관련 코드를 보면 이해하기 좋다.
private async UniTask Timeout(UniTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime,
PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update,
CancellationTokenSource taskCancellationTokenSource = null) {
var delayCancellationTokenSource = new CancellationTokenSource();
var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token)
.SuppressCancellationThrow();
int winArgIndex;
bool taskResultIsCanceled;
try {
(winArgIndex, taskResultIsCanceled, _) =
await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);
} catch {
delayCancellationTokenSource.Cancel();
delayCancellationTokenSource.Dispose();
throw;
}
if (winArgIndex == 1) {
if (taskCancellationTokenSource != null) {
taskCancellationTokenSource.Cancel();
taskCancellationTokenSource.Dispose();
}
UtilMethod.ShowToast(UtilMethod.GetLocalizedText("message_load_failed"), TOAST_CODE.ERROR);
throw new TimeoutException("Exceed Timeout:" + timeout);
} else {
delayCancellationTokenSource.Cancel();
delayCancellationTokenSource.Dispose();
}
if (taskResultIsCanceled) {
throw new OperationCanceledException();
}
}
UniTask.Delay안에 새로운 Cancellation토큰을 만들어 넣어주어 timeout task를 만들어 준다. 내 loadingTask와 UniTask.Delay중 먼저 끝나는 task를 UniTask.WhenAny로 판단 -> 먼저, 끝난 게 timeout task라면 타임아웃이라는 메세지와 함께 loadingTask의 token을 취소해준다. 그게 아니라면 delay token을 취소해준다.
Task를 메뉴얼로 조작 하는 법은 위의 예시가 잘 보여 준다고 생각한다.
혹은 반복문은 중간에 종료 하는 방식으로 cancellation token source의 IsCancellationRequested를 체크하는 방식으로 사용할수 있다.
while(true) {
if(cancelToken.IsCancellationRequested){
return;
}
Debug.Log("loop in process");
}
UniTask 작업 확인
UniTaskTracker가 있다. Unitask안에서 일어나는 작업들을 확인 해볼수 있으니 유용하다. 어디서 task를 콜하고 있는지 StackTrace로 디버깅하면서 이용하면 유용하다.
UniTask의 UnitTesting
[UnityTest]
public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () =>
{
var time = Time.realtimeSinceStartup;
Time.timeScale = 0.5f;
try
{
await UniTask.Delay(TimeSpan.FromSeconds(3), ignoreTimeScale: true);
var elapsed = Time.realtimeSinceStartup - time;
Assert.AreEqual(3, (int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven));
}
finally
{
Time.timeScale = 1.0f;
}
});
UniTask를 Corountine으로 변환
'Game Dev > Unity' 카테고리의 다른 글
게임 엔진의 역사와 동작 원리 - (24절기 발표 내용) (0) | 2023.06.25 |
---|---|
Unity - Nuget 패키지 적용 하는 법 (1) | 2023.05.19 |
Unity 리소스 관리 - 어드레서블(Addressable) (0) | 2023.04.23 |
TestRunner - Unity 테스트 환경 (feat. 테스트 코드의 중요성) (0) | 2023.04.23 |
Unitask의 정체 - (feat. task, 비동기, Unity는 싱글스레드?) (0) | 2023.04.09 |