92.2K Views
April 13, 22
スライド概要
某サークルで開催されたLT会の登壇資料です。キャンセルや失敗など、少し追記してます。
脱UniRx&Croutineから始めるUniTask
※ ほぼUnity/C#の話しかしません
話す内容 ● 非同期処理 ● コルーチン ● UniRx ● UniTask ● async/await
非同期処理
非同期処理
の前に
同期処理(sync) 処理が終わって結果が返ってくるまで待つ。
非同期処理(async) 処理が終わるのを待たずに次の処理を実行する
Unityの非同期処理 ● MonoBehaviour.Invoke ● コルーチン ● Task ● DOTween ● UniRx ● UniTask
Unityの非同期処理 ● MonoBehaviour.Invoke ● コルーチン ● Task ● DOTween ● UniRx ● UniTask
UniTask ● UniRxの作者であるneueccさんが公開しているOSS ● 実務での採用実績もたくさん ● 素では使いにくい Task をUnity向けに1から実装したもの(Task-like) ● Unity独自の非同期処理を async / await で待てる ● めっちゃ軽い(ゼロアロケーション)
Q. async/await を使うと Unity の API 使えないんじゃないの? A. 使えます
async / await ● 名前の通り非同期処理を待つための機構 ● 非同期処理 ≠ マルチスレッド ○ 相性は良いが非同期とマルチスレッドは違う話 ○ Unity 固有の非同期処理はシングルスレッドで実現されている ● 非同期処理の連結を手続き的に書ける ○ Unityコルーチンのyield return に近い ○ 同期処理とあまり変わらない構文で非同期処理を書くことができる ● UniTaskを使えばUnityでもガンガン使えて超便利 ○ UniTaskはPlayerLoopを使って動いている
脱Coroutine
async/awaitの書き方はコルーチンに似てる コルーチン ● 非同期メソッドには async 修飾子を付ける ● 非同期メソッドを待つときは await を付ける ● asyncをつけたメソッドの中でしかawaitは使えない UniTask
コルーチンにはできないこともasync/awaitならできる ● StartCoroutineが無くても動く ● ジェネリックで型を指定して値をreturnで返せる
コルーチンにはできないこともasync/awaitならできる ● try-catchでエラーハンドリングできる ○ ○ try構文の中ではyieldは使えないがawaitはできる エラーの種類で処理変えたり
コルーチンにはできないこともasync/awaitならできる ● 並行処理も待てる ○ コルーチンには複数の非同期処理を並行で待つ機能はない ○ UniTaskでは WhenAll や WhenAny を使う
脱UniRx
UniRx ● neueccさんが公開している言わずと知れたUnityのRxライブラリ ● オブザーバーパターンをベースに作られている ● C#のeventの上位互換みたいなやつ
Observable.Timer系の出番はもうない DelayとかDelayFrameとか超便利 明らかにObservableで書いたときよりスッキリしてる
結果が1つものはUniTask化すると良い async/await は 結果が必ず1つになるので Firstオペレータ を使う前提のストリームや AsyncSubject は UniTask に変えたほうが扱いやすい 【例】 ● オブジェクトの初期化 ● ゲーム開始・終了の通知 ● 死亡通知 ● etc...
UniRx, UniTask, コルーチンの使い分け ● 基本は async/await での実装を考える ○ async/awaitでは表現できそうになかったら Rx ● 軽い指標として ○ 結果が1つのものは async/await ○ 結果が不定(0, 1, ∞)のものは Rx(イベントとか) ● 非同期処理を手軽に一時停止や再起動するならコルーチン ○ StopCoroutine → StartCoroutine で簡単に一時停止・再起動できる ○ UniTask には途中で一時停止等する機能はない
キャンセル ● 非同期処理はキャンセルがめっちゃ大事 ○ UniRx…IDisposable.Dispose ○ コルーチン…StopCoroutine,GameObjectのDestroy ● UniTaskのキャンセルはCancellationTokenを使う ○ System.Threadingに定義されている(C#標準) ○ Task,ValueTaskと同じ
キャンセル ● CancellationTokenがキャンセル命令を検知して例外をスローする ○ OperationCanceledException ● キャンセル命令はCancellationTokenSourceのCancelメソッドで行う
キャンセル ● MonoBehaviourの場合はGetCancellationTokenOnDestroy()が便利 ○ OnDestroyのタイミングでキャンセルするCancellationTokenを取得できる
失敗とキャンセル ● キャンセル… OperationCanceledException ● 失敗…OperationCanceledException以外の例外 キャンセルは上流まで伝播させる必要がある
今回話せなかったけど大事なこと ● 色々なもの to UniTask ● ファクトリ,インスタンスメソッド ● UniTaskCompletionSource ● UniTaskVoid ● UniTaskTracker ● UniTaskAsyncEnumerable ● etc…
まとめ ● 非同期処理は結果を待たずに次の処理を実行すること ● 非同期処理 ≠ マルチスレッド ● UniTask を使えば Unity でも async/await が快適に使える ● Rxでは煩わしかった深いネストや非同期処理の直列実行をasync/awaitで楽に書 くことができる ● キャンセル大事!サボらない ● 便利機能たくさん
おすすめの本 UniRx/UniTask完全理解 より高度なUnity C#プログラミング 著作: 打田恭平