UniTask 에서 Token(CancellationToken) 은 쉽게 말하면, "멈춰!" 토큰입니다.

Token (= CancellationToken)
토큰은 비동기 작업이 더 이상 의미가 없을 때, 바로 멈출 때가 되었다고 알려주는 플래그 같은 것입니다.
프로그램(게임)에서 기다리던 작업을 계속할 이유가 없어졌을 때, 토큰으로 취소하게 됩니다.
(유니테스크 간단 정리는 아래 포스트에 해두었어용)
https://bulletprooves.tistory.com/87
[Unity] UniTask
UniTask 와 코루틴을 비교해서 설명하면 이해가 쉽다고 합니다. UniTaskUnity 에서 사용하는 Task 대체 라이브러리라서 UniTask 라고 부릅니다.C# 의 async/await 구문을 좀 더 유니티에 최적화해 사용할 수
bulletprooves.tistory.com
일반적으로 생성 -> 전달 -> 취소 순으로 사용합니다.
먼저 아래와 같이 필드로 둘 수 있습니다.
private CancellationTokenSource _token = null;
생성(초기화)는 아래와 같은 단계로 진행하면 됩니다.
void OnEnable()
{
// 만약 이전 토큰이 있다면 취소 후 해제하는게 좋지요
_token?.Cancel();
_token?.Dispose();
// 새 토큰 발급(생성)
_token = new CancellationTokenSource();
// 오브젝트 파괴 시 자동 취소되도록 링크합니다 (선택사항이에용)
var destroyToken = this.GetCancellationTokenOnDestroy();
_token = CancellationTokenSource.CreateLinkedTokenSource(_token.Token, destroyToken);
// 비동기 작업 시작 (안에서 반드시 _token.Token을 전달!)
RunAsync(_token.Token).Forget();
}
await 가 가능한 곳에 넣어 사용할 수 있습니다. (전달)
private async UniTask RunAsync(CancellationToken ct)
{
try
{
// 조건이 만족할 때까지 기다려용 (IsReady 는 부울타입의 변수)
await UniTask.WaitUntil(() => IsReady, cancellationToken: ct);
// 일정 시간(1.5초) 기라립니다요
await UniTask.Delay(TimeSpan.FromSeconds(1.5f), cancellationToken: ct);
// 리소스 로드(+ 사운드 매니저같은 싱글톤이 있다는 가정 하에 아래처럼 불러오겠습니다용)
var clip = await SoundManager.Instance.LoadAssetAsync<AudioClip>("path/ang.wav", ct);
// 메인 스레드에서 업데이트하여 진행하도록 합니다 (필요시 아래처럼 쓰면 돼용)
await UniTask.SwitchToMainThread(ct);
if (clip != null)
SoundManager.Instance.PlaySound(clip);
}
catch (OperationCanceledException)
{
// 취소는 정상 흐름이므로 조용히 종료하도록
}
catch (Exception ex)
{
Debug.LogException(ex); // 진짜 에러만 로깅하도록
}
}
아래 처럼 오브젝트가 그만두게 될 때 취소합니다.
void OnDisable()
{
_token?.Cancel(); // 진행 중 대기/로드 그냥 바로 중단 때리기
_token?.Dispose(); // 핸들 해제
_token = null;
}
await
말 그대로 "기다려!" 하는 거 랍니다.
해당 비동기 작업이 끝날 때까지, 메인 스레드(Unity 는 메인스레드)를 막지말고 잠깐 멈추라는 뜻 입니다.
코드의 논리적인 흐름은 동기처럼 읽히게 되지만, 실제 프로그램(게임)의 frame 을 blocking 하지 않습니다.
(잠깐 await 하는 동안, 렌더링이나 입력 처리 등의 다른 일은 계속하게 되는 거죠)
SomeAsync().Forget(); // 기다리지 않습니다, 이 메서드는 그냥 무시~
await SomeAsync(); // 끝날 때까지 논리적으로 대기합니다
Static (정적) 유틸리티로 관리하기 (Facade)
아래처럼 싱글톤으로 토큰을 관리할 수도 있겠습니다만,
public static UniTaskManager Instance { get; private set; }
아래 처럼 static class 유틸리티 처럼 쓰는 것도 간단하고 괜찮은 방법입니다.
using System;
using System.Threading;
using UnityEngine;
using Cysharp.Threading.Tasks;
public static class UniTaskManager
{
public static void CancelUniTaskToken(ref CancellationTokenSource cts, GameObject owner, CancellationToken parent = default)
{
// #1 이전 토큰 정리 해버리기
try
{
if (cts != null && !cts.IsCancellationRequested)
cts.Cancel();
}
catch (ObjectDisposedException)
{
//이미 해제된 경우에는 무시
}
finally
{
cts?.Dispose();
cts = null;
}
// #2 owner 가 없으면 새로 만들 필요 없음
if (owner == null)
return;
// #3 owner 파괴 시 취소되는 토큰
var destroyToken = owner.GetCancellationTokenOnDestroy();
// #4 링크 토큰 소스 생성 (owner 파괴 부모 토큰)
if (parent.CanBeCanceled)
{
cts = CancellationTokenSource.CreateLinkedTokenSource(destroyToken, parent);
}
else
{
cts = CancellationTokenSource.CreateLinkedTokenSource(destroyToken);
}
}
}
위처럼 구현해놨을 경우 아래처럼 ref 로 돌려주는 메서드 (helper) 로 사용할 수 있습니다. (Facade 퍼사드)
private CancellationTokenSource _token;
void OnEnable()
{
UniTaskManager.CancelUniTaskToken(ref _token, this.gameObject);
RunAsync(_token.Token).Forget();
}
void OnDisable()
{
UniTaskManager.CancelUniTaskToken(ref _token, this.gameObject);
// 이전 것 취소(Dispose), 새로 만들 필요 없으면 null 로 두게 됩니다
_token = null;
}
기존의 cts 가 살아있다면, Cancel -> Dispose -> null 순으로 정리되겠습니다.
owner.GetCancellationTokenOnDestroy() 를 링크하면 오브젝트가 파괴될 때 자동으로 취소되게 됩니다.
그러나 상위 흐름에 토큰이 있다먄, 위처럼 parent 로 추가 링크를 둬 글로벌적인 취소도 함께 반영되도록 합니다.
why?
왜 이렇게 까지 해두게 되는지는 아래와 같은 이유 때문입니다.
1. 이미 사라진 UI를 대상으로 콜백이 돌아오면 널참조 (NRE) 에러 위험 예방
2. 더 이상 필요 없는 대기나 로딩을 즉시 끊어 리소스 아끼기
3. 화면이 바뀌었는데도 이전 작업이 끝나길 기다리게 됐을 때, 유저기 느낄 게임이 끊긴 현상(?)을 예방
위 같은 이유 때문에 task 관리를 잘 할 수 있도록 UniTask 를 사용하게 됩니다.
정리
마지막으로 요약하면 아래와 같이 체크리스트를 만들 수 있겠습니다.
- 생성 및 초기화 : 이전의 것을 Cancel / Dispose 후, 새롭게 CancellationTokenSource()
- 전달 : 모든 await 가능한 호출에 cancellationToken: _token.Token 하여 전달
- 정리 : OnDisable, OnDestroy 등 에서 Cancel / Dispose / null
( - 예외 처리 : OperationCanceledException 은 정상 취소 -> 조용히 반환)
( - 하위 함수 : 토큰을 “계속 전달”하는 시그니처 유지)
실컷 놀다가 정리하고 나니 새벽 2시네요~ @.@
그럼 이만 좋은 저녁 되시길 바랍니당 (っ ̯ -。)
'- Unity > let us all UNITE !' 카테고리의 다른 글
| [Unity] AsyncOperationHandle (0) | 2025.12.02 |
|---|---|
| [Unity] LoadAssetAsync Release InstantiateAsync ReleaseInstance (0) | 2025.12.02 |
| [Unity, C#] Singleton 싱글톤 (0) | 2025.09.07 |
| [Unity] UniTask (3) | 2025.07.10 |
| [Unity] UniTask (0) | 2025.07.03 |