こんにちは、Unityエンジニアのオオバです。
Unityをお使いのみなさまasync/await
便利ですよね。
コルーチンと比べてコードがスッキリ しました。
今やUnityで非同期は UniTask一択 です。
async/await登場前の非同期処理は コルーチン でした。
もちろん今でもコルーチンは使えますし、使っている現場はあります。
しかし、コルーチンと比べて UniTaskのキャンセル処理が難しい という声をよく聞きます。
本記事では UniTaskのキャンセル処理について初心者向けに解説 します。
UniTaskにおいてキャンセル処理は鬼門 なので気合を入れて
丁寧に説明していきますね!
→11万文字で徹底解説した「DOTweenの教科書」Unityアニメーションの超効率化ツールはこちら
UniTaskのキャンセルにはCancellationTokenを使う
いつもどおり結論から解説はしますが、
いきなり CancellationToken
と言われても。。。
という感じかもしれません。
詳しい解説は後ほどしますが、ここでは簡潔にまとめます。
- UniTaskはGameObjectのOFFでは止まらない
- UniTaskはCancellationTokenで停止する
- 理想は全てのUniTaskにCancellationTokenを渡すべき
UniTaskはGameObjectのOFFでは止まらない
こちらは前回解説した内容です。
そう、 GameObjectがDestroyしても
UniTaskは動き続けます。
UniTaskのキャンセル処理についての詳細を解説していきます。
UniTaskはGameObjectのOFFでは止まらない
コルーチンからUniTaskに切り替えた時、
最初につまづく点は GameObjectに
UniTaskがひも付かない点 です。
💻ソースコード : UniTaskがGameObjectのOFFで停止しないサンプル
async void Start()
{
TestUniTask();
gameObject.SetActive(false);
}
async UniTask TestUniTask()
{
await UniTask.Delay(1000);
Debug.Log("Unitask完了");
}
UniTask実行直後にGameObjectを非アクティブにしています。
コルーチンなら止まっていたわけですが、
UniTaskは止まりません。
1秒後のログがしっかり出力されます。
つまりUniTaskとGameObjectは分離して考えましょう。
まずはここからです。
UniTaskはCancellationTokenで停止する
UniTaskのキャンセルとは、
非同期処理をするUniTaskの停止 を指します。
UniTaskを停止させるサンプルコードはこちらです。
async Start()
{
var cts = new CancellationTokenSource();
CancellationToken token = cts.token;
Wait5SecUniTask(token);
await UniTask.Delay(TimeSpan.FromSeconds(1));
// UniTaskのキャンセル実行
cts.Cancel();
}
async UniTask Wait5SecUniTask(CancellationToken token)
{
await UniTask.Delay(TimeSpan.FromSeconds(5), token);
Debug.Log("Complete!");
}
CancellationTokenSource
のCancel
メソッドで停止します。
- CancellationToken
- CancellationTokenSource
登場したこの2つについて解説していきます。
ここはとても重要なところです。
CancellationTokenSourceから生まれるCancellationToken
CancellationToken
とCancellationTokenSource
は
UniTaskのキャンセルに必要な要素です。
var cts = new CancellationTokenSource();
CancellationToken token = cts.token;
↑のとおりCancellationToken
は、
CancellationTokenSource
から生成します。
cts.Cancel();
↑UniTaskをキャンセルするときは、
CancellationTokenSource
の
Cancelメソッド を呼びます。
例えば UniTask.Delay()
はキャンセルに対応しています。
await UniTask.Delay(1000, token);
第2引数にCancellationToken
を代入すれば
キャンセルすることができます。
UniTask(async/await)の世界を渡り歩くためには
CancellationToken、
CancellationTokenSourceの理解は必須です。
あいまいな状態にしておくと
思わぬエラー、メモリリークなどを引き起こします。
複数のUniTaskを同時にキャンセルさせる
CancellationToken
とCancellationTokenSource
の
理解を深めるために複数のUniTaskを
同時にキャンセルさせるサンプルを作ってみます。
複数のUniTaskを同時にキャンセルさせたい場合は、
1つのCancellationTokenSourceから作った
CancellationTokenをそれぞれのUniTaskに渡します。
async void Start()
{
var cts = new CancellationTokenSource();
CancellationToken token = cts.token;
TestUniTask(1, token);
TestUniTask(2, token);
TestUniTask(3, token);
TestUniTask(4, token);
await UniTask.Delay(TimeSpan.FromSeconds(1));
// ctsに紐づくTaskがキャンセルされる
cts.Cancel();
}
async UniTask TestUniTask(int id, CancellationToken token)
{
await UniTask.Delay(TimeSpan.FromSeconds(5), token);
Debug.Log($"UniTask : {id} 完了");
}
なんとなくわかってきましたでしょうか。
キャンセル処理は例外あつかい
UniTaskの停止は理解できたと思います。
ではキャンセル後の分岐はどうすればよいか。
結論、try-catch
を使います。
次のコードを見てみましょう。
💻ソースコード : UniTaskのキャンセル分岐サンプル
CancellationTokenSource _cts;
async void Start()
{
_cts = new CancellationTokenSource();
try {
await TestUniTask(_cts.token);
Debug.Log("UniTask完了");
}
catch (OperationCanceledException e){
// キャンセル時に呼ばれる例外
Debug.Log("Taskキャンセル時の処理");
}
}
// ボタンをクリックしたらCancel実行
void OnClick() => _cts?.Cancel();
例としてキャンセルボタンをクリックしたら
UniTaskがキャンセルされるサンプルです。
try節
の中でUniTaskを実行し、
catch節
の中でキャンセル時の分岐を記述します。
CancellationTokenSource
のCancel
を実行すると
OperationCanceledException という
例外がスローされます。
この例外をもとにキャンセル後の処理を実行するというわけです。
つまりUniTaskのキャンセルとは例外扱いだということです。
今までtry-catchはエラーやヌルポ、ミスや間違いといった
例外をチェックするために使っていましたが、
キャンセルも例外としてとらえる必要が出てきた
ということです。
マインドを変える必要があります。
まとめ : async/awaitを使う上でUniTaskのキャンセルは例外処理です
UniTaskのキャンセルについて解説しました。
記事の内容を簡単にまとめます。
- UniTaskはGameObjectのOFFでは停止しない
- UniTaskのキャンセルにはCancellationTokenを使う
- UniTaskのキャンセルは例外処理である
こんな感じです。
UniTask(async/await)によって
得られる絶大なメリットと引き換えに
コルーチンと比べると複雑になったキャンセル処理。
重要なのはキャンセルは例外であるという意識です。
コルーチンに慣れ過ぎていると、
async/awaitの感覚は掴みづらいかも知れません。
しかし一度UniTaskに慣れると便利すぎて戻れないです。
ぜひUniTaskを使った非同期処理に挑戦してもらえればと思います。

この記事が気に入ったらフォローしよう
TikTokを始めました!!毎朝7時から自作ゲーム開発を配信しています。
ぜひフォローをお願いします!
最後まで読んでいただきありがとうございました!
すばらしいUniTaskライフをお過ごしください。
- Unity2020.3.15f2
- UniTask v2.2.5