UniTask入門
by
torisoup
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
UniTask⼊⾨ 2019/07/20 とりすーぷ
Slide 2
Slide 2 text
⾃⼰紹介 • とりすーぷ • @toRisouP • バーチャルキャスト社 • Unityエンジニア • 最近はサーバ開発 • MagicOnion, k8s • Microsoft MVP 2018〜 • Developer Technology
Slide 3
Slide 3 text
今回の内容「UniTask」 • UniTaskの概要 • UniTaskの使い⽅ • 機能紹介 • キャンセル管理について
Slide 4
Slide 4 text
UniTaskの概要
Slide 5
Slide 5 text
UniTaskとは •Unity向けasync/await拡張ライブラリ • Unityの標準機能ではない、⾃分で導⼊が必要な外部ライブラリ • 株式会社Cysharpさんが提供 • 主開発はneuecc⽒(UniRxの作者) • 前はUniRxの⼀部だったが、後に分離したライブラリ化された • その名残で名前空間が「UniRx.Async」のまま
Slide 6
Slide 6 text
UniTaskでできること • 「async/awaitでなんでもできるようになる」 • コルーチンをasync/awaitに置き換え • Unityイベント関数のawait • UnityEditor上でawait状況の可視化
Slide 7
Slide 7 text
例:コルーチンの置き換え
Slide 8
Slide 8 text
例:コルーチンの置き換え コルーチンから結果を取りだすためのデリゲート
Slide 9
Slide 9 text
例:コルーチン -> UniTask
Slide 10
Slide 10 text
例:コルーチン -> UniTask
Slide 11
Slide 11 text
例:コルーチン -> UniTask 結果はそのままreturnすればOK 例外もthrowするだけ
Slide 12
Slide 12 text
UniTaskを使うメリット • コルーチンを使う必要がなくなる • より使いやすいasync/awaitですべてを記述できる • 既存のTaskよりもハイパフォーマンス • Unityに最適化されたTask-likeな機構が使える • UniRxよりはわかりやすい • ⼿続き処理で書ける、は⼗分メリット
Slide 13
Slide 13 text
導⼊⽅法 • GitHubからunitypackageをダウンロードしてインポート • https://github.com/Cysharp/UniTask/releases • AssetStoreにはまだ公開されていない
Slide 14
Slide 14 text
UniTaskが使える条件 • C# 7以降が使えるUnityであること • Unity 2018.3 以降 • Unity 2018.2 以前はIncremental Compilerを導⼊していると使える
Slide 15
Slide 15 text
UniTaskの機能紹介
Slide 16
Slide 16 text
UniTaskが提供する機能 • UniTask型、UniTask型 • UniTaskに付随するstaticメソッド群 • Unity機能のAwaiter • UniTaskTracker
Slide 17
Slide 17 text
UniTaskが提供する機能 • UniTask型、UniTask型 • UniTaskに付随するstaticメソッド群 • Unity機能のAwaiter • UniTaskTracker
Slide 18
Slide 18 text
UniTask型/UniTask型 UniTaskの機能紹介
Slide 19
Slide 19 text
UniTask型/UniTask型 • Unity⽤に最適化されたTask-likeオブジェクト • Task/TaskのUnity向け実装 • Taskの基本機能はだいたい使える
Slide 20
Slide 20 text
Task型 vs UniTask型 Task UniTask 機能 Unityでは不要な機能が多い Unityで活⽤できる機能のみ オブジェクトサイズ ムダに⼤きい ⼩さい 実⾏コンテキスト管理 TaskScheduler & SynchronizationContext PlayerLoop 必要なC# version C# 5.0以上 C# 7.0以上 Task Tracker 無 Unity Editor上で利⽤可能
Slide 21
Slide 21 text
UniTask型の作り⽅ 作り⽅は主に3パターン ・async/awaitの戻り値として使う ・UniTaskCompletionSourceから作る ・Observableから変換する
Slide 22
Slide 22 text
UniTask型の作り⽅ 作り⽅は主に3パターン ・async/awaitの戻り値として使う ・UniTaskCompletionSourceから作る ・Observableから変換する
Slide 23
Slide 23 text
例: async/awaitから作る • async/awaitの戻り値をUniTaskに書き換えるだけでOK • これだけでTask型からUniTask型に変換される
Slide 24
Slide 24 text
例: async/awaitから作る • ジェネリック版のときも同様 • Task を UniTask に置き換えるだけ
Slide 25
Slide 25 text
(補⾜) UniTaskVoid型 • UniTaskの機構に乗った ”async void” • 投げっぱなし(Fire-and-forget)の⾮同期処理として使う
Slide 26
Slide 26 text
UniTask型の作り⽅ 作り⽅は主に3パターン ・async/awaitの戻り値として使う ・UniTaskCompletionSourceから作る ・Observableから変換する
Slide 27
Slide 27 text
UniTaskCompletionSource • ⼿続き処理でUniTaskを⽣成するときに使う • UniRxのAsyncSubjectとだいたい同じ
Slide 28
Slide 28 text
UniTaskCompletionSource
Slide 29
Slide 29 text
UniTask型の作り⽅ 作り⽅は主に3パターン ・async/awaitの戻り値として使う ・UniTaskCompletionSourceから作る ・Observableから変換する
Slide 30
Slide 30 text
Observableからの変換 • UniTaskとObservable(UniRx)は相互変換可能
Slide 31
Slide 31 text
注意点1 • Observableが必ず完了する状態にすること • useFirstValue=true でTake(1)と同等になる
Slide 32
Slide 32 text
注意点2 • UniTask -> Observable 時、 実⾏コンテキストは必ずメインスレッドになる
Slide 33
Slide 33 text
UniTask/UniTask型 まとめ • 使い勝⼿は標準Taskとほとんど同じ • 既存のasyncメソッドを機械的に置換して問題ない • Observableが絡む時だけちょっと注意が必要
Slide 34
Slide 34 text
UniTaskが提供する機能 • UniTask型、UniTask型 • UniTaskに付随するstaticメソッド群 • Unity機能のAwaiter • UniTaskTracker
Slide 35
Slide 35 text
Staticメソッド群 UniTaskの機能紹介
Slide 36
Slide 36 text
UniTaskに付随するstaticメソッド群 • 特殊な挙動をするUniTaskを⽣成できるメソッド群 • FactoryMethod的なやつ • ほとんどがawaitとの併⽤がメイン
Slide 37
Slide 37 text
UniTask.Run • デリゲートをThreadPool上で実⾏する • Task.Runと挙動はおなじ • await後はUnityメインスレッドに戻る(configureAwait = true の時)
Slide 38
Slide 38 text
UniTask.Delay • 指定秒数後に完了するUniTaskを⽣成する • awaitすることで「⼀定時間待つ」ができる • どのタイミングで時間計測するか選べる • デフォルトはUpdate()タイミングで計測
Slide 39
Slide 39 text
UniTask.DelayFrame • 指定フレーム後に完了するUniTaskを⽣成する • awaitすることで「⼀定フレーム待つ」ができる • どのタイミングで計測するか選べる • デフォルトはUpdate()タイミング
Slide 40
Slide 40 text
UniTask.Yield() • 指定のタイミングで1フレーム待機する • 処理をメインスレッドに戻すことにも使える • 引数なしの場合はUpdateタイミングで1フレーム待機になる
Slide 41
Slide 41 text
UniTask.Yield
Slide 42
Slide 42 text
UniTask.SwitchToThreadPool • 実⾏コンテキストをThreadPoolに切り替える • awaitするとそれ以降がThreadPool上での処理になる • 似たものでSwitchToTaskPoolがあるが、こっちは⾮推奨
Slide 43
Slide 43 text
UniTask.SwitchToThreadPool
Slide 44
Slide 44 text
UniTask.SwitchToMainThread • 実⾏コンテキストをメインスレッドに切り替える • awaitするとそれ以降がメインスレッド上での処理になる • UniTask.Yield(PlayerLoopTiming.Update)と微妙に挙動が異なる
Slide 45
Slide 45 text
UniTask.WaitUntil / UniTask.WaitWhile • 条件を満たすまで/満たさなくなるまで待機する • コルーチンのWaitUntil/WaitWhileと同等 • どのPlayerLoopタイミングでチェックするかも指定できる
Slide 46
Slide 46 text
UniTask.WaitUntil / UniTask.WaitWhile
Slide 47
Slide 47 text
UniTask.WaitUntilValueChanged • 指定のオブジェクトのパラメータが変動するまで待機する • UniRxのObserveEveryValueChangedと同じ • 対象は弱参照で保持され、GCされるとawaitはキャンセルされる
Slide 48
Slide 48 text
UniTask.WhenAll • 指定のUniTaskがすべて完了するまで待機する • UniTaskの型がすべて⼀致していなくてもOK
Slide 49
Slide 49 text
UniTask.WhenAll
Slide 50
Slide 50 text
UniTask.WhenAny • 複数のUniTaskのうちどれか1つが先に完了するまで待機する
Slide 51
Slide 51 text
Staticメソッド群 まとめ • Unity向けに調整された機能が多くて便利 • 標準Taskとくらべて使いやすくなってたりもする • まだまだあるけど量が多いので省略
Slide 52
Slide 52 text
UniTaskが提供する機能 • UniTask型、UniTask型 • UniTaskに付随するstaticメソッド群 • Unity機能のAwaiter • UniTaskTracker
Slide 53
Slide 53 text
Awaiter UniTaskの機能紹介
Slide 54
Slide 54 text
Awaiterって何 • オブジェクトのawaitに必要なヤツ • あるオブジェクトにGetAwaiter()メソッドが実装されており、 そこからAwaiterが取得できるならそのオブジェクトはawaitができる
Slide 55
Slide 55 text
補⾜:GetAwaiter() • Awaiterを取得するためのメソッド • クラスメソッドだけでなく、拡張メソッドでもOK • ⾃前で実装すればなんでもawaitできるようになる awaitにカーソルを合わせて定義元を参照するとどのGetAwaiter()が呼ばれるかわかる
Slide 56
Slide 56 text
UniTaskとAwaiter • UniTaskはUnityのあらゆるオブジェクトの Awaiterを提供してくれる
Slide 57
Slide 57 text
UniTaskが提供するAwaiter • コルーチン • AsyncOperation • uGUI Event • Unityコールバック • JobHandle • UnityEvent
Slide 58
Slide 58 text
コルーチンのAwaiter • IEnumeratorをawaitするとコルーチンとして実⾏&待機する
Slide 59
Slide 59 text
コルーチンのAwaiter
Slide 60
Slide 60 text
(補⾜)コルーチン上でUniTask • ToCoroutine()でUniTaskをコルーチン化もできる
Slide 61
Slide 61 text
AsyncOperationのAwaiter
Slide 62
Slide 62 text
AsyncOperationのAwaiter • ConfigureAwaitで進⾏状況取得可能
Slide 63
Slide 63 text
uGUI EventのAwaiter ※using UniRx.Async.Triggers が必要
Slide 64
Slide 64 text
UnityコールバックのAwaiter • MonoBehaviourに⾶んでくるイベントコールバックのこと ※using UniRx.Async.Triggers が必要
Slide 65
Slide 65 text
Awaiter まとめ • Unityのあらゆる要素がawait可能になる • コルーチンの上位互換としてasync/awaitが利⽤可能になる
Slide 66
Slide 66 text
UniTaskが提供する機能 • UniTask型、UniTask型 • UniTaskに付随するstaticメソッド群 • Unity機能のAwaiter • UniTaskTracker
Slide 67
Slide 67 text
UniTaskTracker UniTaskの機能紹介
Slide 68
Slide 68 text
UniTaskTracker • await中のUniTaskを可視化するEditor拡張 • Unity Editorの [Window] -> [UniRx] -> [UniTask Tracker] • UniTaskがリークしていないか確認できる
Slide 69
Slide 69 text
UniTaskとキャンセル
Slide 70
Slide 70 text
⾮同期処理とキャンセル • ⾮同期処理はキャンセルを常に考慮しなくてはいけない • もろもろの理由で不要になった時に 実⾏中の処理を⽌めないといけない
Slide 71
Slide 71 text
UniTaskとキャンセル • UniTaskを使う上でも当然キャンセルの実装が必要 • リソースの解放、適切なタイミングでの停⽌、漏れのない中断、 これらは⼈間が考えて実装する必要がある
Slide 72
Slide 72 text
適切にキャンセルするために • CancellationToken • OperationCanceledException
Slide 73
Slide 73 text
適切にキャンセルするために • CancellationToken • OperationCanceledException
Slide 74
Slide 74 text
CancellationToken • ⾮同期処理にキャンセルを通知するためのC#標準機能 • 「キャンセル要求されたか?」のフラグを持つオブジェクト
Slide 75
Slide 75 text
CancellationToken
Slide 76
Slide 76 text
CancellationToken CanellationTokenSourceから⽣成
Slide 77
Slide 77 text
CancellationToken if⽂で判定 if( IsCancellationRequested ) throw new OperationCanceledException(); の省略記法
Slide 78
Slide 78 text
補⾜: GetCancellationTokenOnDestroy()
Slide 79
Slide 79 text
UniTaskとCancellationToken • UniTaskはCancellationTokenを使ってキャンセル判定を⾏う • キャンセル要求がくるとUniTaskはキャンセル状態になる • await中の場合はそこで処理が終了しawait以降は実⾏されない
Slide 80
Slide 80 text
CancellationTokenは省略しない • 「めんどくさいからキャンセル処理を書かない」はNG
Slide 81
Slide 81 text
Tokenが渡せない処理の場合のキャンセル • CancellationTokenの状態を⼿動で確認する • どのタイミングで処理を⽌めるのか、は⾃分で考える • キャンセル時はOperationCanceledExceptionを発⾏すればOK
Slide 82
Slide 82 text
⼿動でキャンセルチェックする例
Slide 83
Slide 83 text
適切にキャンセルするために • CancellationToken • OperationCanceledException
Slide 84
Slide 84 text
OperationCanceledException • UniTaskをキャンセル状態にするための特殊扱いな例外 • この例外が投げられるとUniTaskは「キャンセル状態」になる • この例外はエラーログに出ない
Slide 85
Slide 85 text
Throwするタイミング • キャンセル要求が外部からされた時にthrowする • 外から「処理を⽌めてね」って⾔われた時に投げる例外 • ⾃⼰判断で勝⼿に投げてよい例外ではない
Slide 86
Slide 86 text
キャンセル要求 • キャンセル要求はCancellationTokenを通じて送られる • ThrowIfCancellationRequested()が便利
Slide 87
Slide 87 text
キャンセルを上流まで伝播させる • この例外は上流まで“貫通”させる • try-catchを書くときはOperationCanceledExceptionだけ 素通りするようにしておく
Slide 88
Slide 88 text
キャンセルを上流まで伝播させる • この例外は上流まで“貫通”させる • try-catchを書くときはOperationCanceledExceptionだけ 素通りするようにしておく
Slide 89
Slide 89 text
悪⽤しない • キャンセル⽤途以外では利⽤しないこと • 本来の⽤途とは別の使い⽅をすると、そこから負債になる • 「処理に失敗したときにエラーログに出したくないから、 OperationCanceledException使っちゃおう」みたいなのはNG
Slide 90
Slide 90 text
No content
Slide 91
Slide 91 text
UniTaskとキャンセル まとめ • CancellationTokenは可能な限り指定する • OperationCanceledExceptionは特殊なので扱いに注意
Slide 92
Slide 92 text
最後のまとめ
Slide 93
Slide 93 text
UniTask、結局何に使えばいいの? • 深く考えず使えそうなところでどんどん使おう • コルーチンの代替として使える • 他のコンポーネントが処理を終えるのを待つ、とかにも使える • むしろUniTaskが使えないことがストレスになるくらいには便利
Slide 94
Slide 94 text
他の⾮同期処理との使い分けは? • async/awaitを使うなら、UniTaskをまず使う • 理由が無い限り標準Taskは使わない • UniRx(Observable)は⽤途に応じて使う • Observableはイベント処理や、結果が複数になる⾮同期処理向け • Observableもawait可能だし、UniTaskとの相互変換もできる
Slide 95
Slide 95 text
まとめ • UniTaskめっちゃ便利だから使おう!!!! • あと今回の話の補⾜的なのをUniBook11に書きました • さらにUniRx+UniTask本、マダカイテルカラマッテネ…