Upgrade to Pro — share decks privately, control downloads, hide ads and more …

UniTask入門

 UniTask入門

Unity++ 〜ショートセッション勉強会 presented by Unity部〜
https://meetup.unity3d.jp/jp/events/1112

E97091ac0d2c69ce9f9e8a8d0a2ea066?s=128

torisoup

July 20, 2019
Tweet

More Decks by torisoup

Other Decks in Technology

Transcript

  1. UniTask⼊⾨ 2019/07/20 とりすーぷ

  2. ⾃⼰紹介 • とりすーぷ • @toRisouP • バーチャルキャスト社 • Unityエンジニア •

    最近はサーバ開発 • MagicOnion, k8s • Microsoft MVP 2018〜 • Developer Technology
  3. 今回の内容「UniTask」 • UniTaskの概要 • UniTaskの使い⽅ • 機能紹介 • キャンセル管理について

  4. UniTaskの概要

  5. UniTaskとは •Unity向けasync/await拡張ライブラリ • Unityの標準機能ではない、⾃分で導⼊が必要な外部ライブラリ • 株式会社Cysharpさんが提供 • 主開発はneuecc⽒(UniRxの作者) • 前はUniRxの⼀部だったが、後に分離したライブラリ化された

    • その名残で名前空間が「UniRx.Async」のまま
  6. UniTaskでできること • 「async/awaitでなんでもできるようになる」 • コルーチンをasync/awaitに置き換え • Unityイベント関数のawait • UnityEditor上でawait状況の可視化

  7. 例:コルーチンの置き換え

  8. 例:コルーチンの置き換え コルーチンから結果を取りだすためのデリゲート

  9. 例:コルーチン -> UniTask

  10. 例:コルーチン -> UniTask

  11. 例:コルーチン -> UniTask 結果はそのままreturnすればOK 例外もthrowするだけ

  12. UniTaskを使うメリット • コルーチンを使う必要がなくなる • より使いやすいasync/awaitですべてを記述できる • 既存のTaskよりもハイパフォーマンス • Unityに最適化されたTask-likeな機構が使える •

    UniRxよりはわかりやすい • ⼿続き処理で書ける、は⼗分メリット
  13. 導⼊⽅法 • GitHubからunitypackageをダウンロードしてインポート • https://github.com/Cysharp/UniTask/releases • AssetStoreにはまだ公開されていない

  14. UniTaskが使える条件 • C# 7以降が使えるUnityであること • Unity 2018.3 以降 • Unity

    2018.2 以前はIncremental Compilerを導⼊していると使える
  15. UniTaskの機能紹介

  16. UniTaskが提供する機能 • UniTask型、UniTask<T>型 • UniTaskに付随するstaticメソッド群 • Unity機能のAwaiter • UniTaskTracker

  17. UniTaskが提供する機能 • UniTask型、UniTask<T>型 • UniTaskに付随するstaticメソッド群 • Unity機能のAwaiter • UniTaskTracker

  18. UniTask型/UniTask<T>型 UniTaskの機能紹介

  19. UniTask型/UniTask<T>型 • Unity⽤に最適化されたTask-likeオブジェクト • Task/Task<T>のUnity向け実装 • Taskの基本機能はだいたい使える

  20. Task型 vs UniTask型 Task UniTask 機能 Unityでは不要な機能が多い Unityで活⽤できる機能のみ オブジェクトサイズ ムダに⼤きい

    ⼩さい 実⾏コンテキスト管理 TaskScheduler & SynchronizationContext PlayerLoop 必要なC# version C# 5.0以上 C# 7.0以上 Task Tracker 無 Unity Editor上で利⽤可能
  21. UniTask型の作り⽅ 作り⽅は主に3パターン ・async/awaitの戻り値として使う ・UniTaskCompletionSourceから作る ・Observableから変換する

  22. UniTask型の作り⽅ 作り⽅は主に3パターン ・async/awaitの戻り値として使う ・UniTaskCompletionSourceから作る ・Observableから変換する

  23. 例: async/awaitから作る • async/awaitの戻り値をUniTaskに書き換えるだけでOK • これだけでTask型からUniTask型に変換される

  24. 例: async/awaitから作る • ジェネリック版のときも同様 • Task<T> を UniTask<T> に置き換えるだけ

  25. (補⾜) UniTaskVoid型 • UniTaskの機構に乗った ”async void” • 投げっぱなし(Fire-and-forget)の⾮同期処理として使う

  26. UniTask型の作り⽅ 作り⽅は主に3パターン ・async/awaitの戻り値として使う ・UniTaskCompletionSourceから作る ・Observableから変換する

  27. UniTaskCompletionSource • ⼿続き処理でUniTaskを⽣成するときに使う • UniRxのAsyncSubjectとだいたい同じ

  28. UniTaskCompletionSource

  29. UniTask型の作り⽅ 作り⽅は主に3パターン ・async/awaitの戻り値として使う ・UniTaskCompletionSourceから作る ・Observableから変換する

  30. Observableからの変換 • UniTaskとObservable(UniRx)は相互変換可能

  31. 注意点1 • Observableが必ず完了する状態にすること • useFirstValue=true でTake(1)と同等になる

  32. 注意点2 • UniTask -> Observable 時、 実⾏コンテキストは必ずメインスレッドになる

  33. UniTask/UniTask<T>型 まとめ • 使い勝⼿は標準Taskとほとんど同じ • 既存のasyncメソッドを機械的に置換して問題ない • Observableが絡む時だけちょっと注意が必要

  34. UniTaskが提供する機能 • UniTask型、UniTask<T>型 • UniTaskに付随するstaticメソッド群 • Unity機能のAwaiter • UniTaskTracker

  35. Staticメソッド群 UniTaskの機能紹介

  36. UniTaskに付随するstaticメソッド群 • 特殊な挙動をするUniTaskを⽣成できるメソッド群 • FactoryMethod的なやつ • ほとんどがawaitとの併⽤がメイン

  37. UniTask.Run • デリゲートをThreadPool上で実⾏する • Task.Runと挙動はおなじ • await後はUnityメインスレッドに戻る(configureAwait = true の時)

  38. UniTask.Delay • 指定秒数後に完了するUniTaskを⽣成する • awaitすることで「⼀定時間待つ」ができる • どのタイミングで時間計測するか選べる • デフォルトはUpdate()タイミングで計測

  39. UniTask.DelayFrame • 指定フレーム後に完了するUniTaskを⽣成する • awaitすることで「⼀定フレーム待つ」ができる • どのタイミングで計測するか選べる • デフォルトはUpdate()タイミング

  40. UniTask.Yield() • 指定のタイミングで1フレーム待機する • 処理をメインスレッドに戻すことにも使える • 引数なしの場合はUpdateタイミングで1フレーム待機になる

  41. UniTask.Yield

  42. UniTask.SwitchToThreadPool • 実⾏コンテキストをThreadPoolに切り替える • awaitするとそれ以降がThreadPool上での処理になる • 似たものでSwitchToTaskPoolがあるが、こっちは⾮推奨

  43. UniTask.SwitchToThreadPool

  44. UniTask.SwitchToMainThread • 実⾏コンテキストをメインスレッドに切り替える • awaitするとそれ以降がメインスレッド上での処理になる • UniTask.Yield(PlayerLoopTiming.Update)と微妙に挙動が異なる

  45. UniTask.WaitUntil / UniTask.WaitWhile • 条件を満たすまで/満たさなくなるまで待機する • コルーチンのWaitUntil/WaitWhileと同等 • どのPlayerLoopタイミングでチェックするかも指定できる

  46. UniTask.WaitUntil / UniTask.WaitWhile

  47. UniTask.WaitUntilValueChanged • 指定のオブジェクトのパラメータが変動するまで待機する • UniRxのObserveEveryValueChangedと同じ • 対象は弱参照で保持され、GCされるとawaitはキャンセルされる

  48. UniTask.WhenAll • 指定のUniTaskがすべて完了するまで待機する • UniTask<T>の型がすべて⼀致していなくてもOK

  49. UniTask.WhenAll

  50. UniTask.WhenAny • 複数のUniTaskのうちどれか1つが先に完了するまで待機する

  51. Staticメソッド群 まとめ • Unity向けに調整された機能が多くて便利 • 標準Taskとくらべて使いやすくなってたりもする • まだまだあるけど量が多いので省略

  52. UniTaskが提供する機能 • UniTask型、UniTask<T>型 • UniTaskに付随するstaticメソッド群 • Unity機能のAwaiter • UniTaskTracker

  53. Awaiter UniTaskの機能紹介

  54. Awaiterって何 • オブジェクトのawaitに必要なヤツ • あるオブジェクトにGetAwaiter()メソッドが実装されており、 そこからAwaiterが取得できるならそのオブジェクトはawaitができる

  55. 補⾜:GetAwaiter() • Awaiterを取得するためのメソッド • クラスメソッドだけでなく、拡張メソッドでもOK • ⾃前で実装すればなんでもawaitできるようになる awaitにカーソルを合わせて定義元を参照するとどのGetAwaiter()が呼ばれるかわかる

  56. UniTaskとAwaiter • UniTaskはUnityのあらゆるオブジェクトの Awaiterを提供してくれる

  57. UniTaskが提供するAwaiter • コルーチン • AsyncOperation • uGUI Event • Unityコールバック

    • JobHandle • UnityEvent
  58. コルーチンのAwaiter • IEnumeratorをawaitするとコルーチンとして実⾏&待機する

  59. コルーチンのAwaiter

  60. (補⾜)コルーチン上でUniTask • ToCoroutine()でUniTaskをコルーチン化もできる

  61. AsyncOperationのAwaiter

  62. AsyncOperationのAwaiter • ConfigureAwaitで進⾏状況取得可能

  63. uGUI EventのAwaiter ※using UniRx.Async.Triggers が必要

  64. UnityコールバックのAwaiter • MonoBehaviourに⾶んでくるイベントコールバックのこと ※using UniRx.Async.Triggers が必要

  65. Awaiter まとめ • Unityのあらゆる要素がawait可能になる • コルーチンの上位互換としてasync/awaitが利⽤可能になる

  66. UniTaskが提供する機能 • UniTask型、UniTask<T>型 • UniTaskに付随するstaticメソッド群 • Unity機能のAwaiter • UniTaskTracker

  67. UniTaskTracker UniTaskの機能紹介

  68. UniTaskTracker • await中のUniTaskを可視化するEditor拡張 • Unity Editorの [Window] -> [UniRx] ->

    [UniTask Tracker] • UniTaskがリークしていないか確認できる
  69. UniTaskとキャンセル

  70. ⾮同期処理とキャンセル • ⾮同期処理はキャンセルを常に考慮しなくてはいけない • もろもろの理由で不要になった時に 実⾏中の処理を⽌めないといけない

  71. UniTaskとキャンセル • UniTaskを使う上でも当然キャンセルの実装が必要 • リソースの解放、適切なタイミングでの停⽌、漏れのない中断、 これらは⼈間が考えて実装する必要がある

  72. 適切にキャンセルするために • CancellationToken • OperationCanceledException

  73. 適切にキャンセルするために • CancellationToken • OperationCanceledException

  74. CancellationToken • ⾮同期処理にキャンセルを通知するためのC#標準機能 • 「キャンセル要求されたか?」のフラグを持つオブジェクト

  75. CancellationToken

  76. CancellationToken CanellationTokenSourceから⽣成

  77. CancellationToken if⽂で判定 if( IsCancellationRequested ) throw new OperationCanceledException(); の省略記法

  78. 補⾜: GetCancellationTokenOnDestroy()

  79. UniTaskとCancellationToken • UniTaskはCancellationTokenを使ってキャンセル判定を⾏う • キャンセル要求がくるとUniTaskはキャンセル状態になる • await中の場合はそこで処理が終了しawait以降は実⾏されない

  80. CancellationTokenは省略しない • 「めんどくさいからキャンセル処理を書かない」はNG

  81. Tokenが渡せない処理の場合のキャンセル • CancellationTokenの状態を⼿動で確認する • どのタイミングで処理を⽌めるのか、は⾃分で考える • キャンセル時はOperationCanceledExceptionを発⾏すればOK

  82. ⼿動でキャンセルチェックする例

  83. 適切にキャンセルするために • CancellationToken • OperationCanceledException

  84. OperationCanceledException • UniTaskをキャンセル状態にするための特殊扱いな例外 • この例外が投げられるとUniTaskは「キャンセル状態」になる • この例外はエラーログに出ない

  85. Throwするタイミング • キャンセル要求が外部からされた時にthrowする • 外から「処理を⽌めてね」って⾔われた時に投げる例外 • ⾃⼰判断で勝⼿に投げてよい例外ではない

  86. キャンセル要求 • キャンセル要求はCancellationTokenを通じて送られる • ThrowIfCancellationRequested()が便利

  87. キャンセルを上流まで伝播させる • この例外は上流まで“貫通”させる • try-catchを書くときはOperationCanceledExceptionだけ 素通りするようにしておく

  88. キャンセルを上流まで伝播させる • この例外は上流まで“貫通”させる • try-catchを書くときはOperationCanceledExceptionだけ 素通りするようにしておく

  89. 悪⽤しない • キャンセル⽤途以外では利⽤しないこと • 本来の⽤途とは別の使い⽅をすると、そこから負債になる • 「処理に失敗したときにエラーログに出したくないから、 OperationCanceledException使っちゃおう」みたいなのはNG

  90. None
  91. UniTaskとキャンセル まとめ • CancellationTokenは可能な限り指定する • OperationCanceledExceptionは特殊なので扱いに注意

  92. 最後のまとめ

  93. UniTask、結局何に使えばいいの? • 深く考えず使えそうなところでどんどん使おう • コルーチンの代替として使える • 他のコンポーネントが処理を終えるのを待つ、とかにも使える • むしろUniTaskが使えないことがストレスになるくらいには便利

  94. 他の⾮同期処理との使い分けは? • async/awaitを使うなら、UniTaskをまず使う • 理由が無い限り標準Taskは使わない • UniRx(Observable)は⽤途に応じて使う • Observableはイベント処理や、結果が複数になる⾮同期処理向け •

    Observableもawait可能だし、UniTaskとの相互変換もできる
  95. まとめ • UniTaskめっちゃ便利だから使おう!!!! • あと今回の話の補⾜的なのをUniBook11に書きました • さらにUniRx+UniTask本、マダカイテルカラマッテネ…