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

torisoup

July 20, 2019
Tweet

More Decks by torisoup

Other Decks in Technology

Transcript

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

    View full-size slide

  2. ⾃⼰紹介
    • とりすーぷ
    • @toRisouP
    • バーチャルキャスト社
    • Unityエンジニア
    • 最近はサーバ開発
    • MagicOnion, k8s
    • Microsoft MVP 2018〜
    • Developer Technology

    View full-size slide

  3. 今回の内容「UniTask」
    • UniTaskの概要
    • UniTaskの使い⽅
    • 機能紹介
    • キャンセル管理について

    View full-size slide

  4. UniTaskの概要

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  13. 導⼊⽅法
    • GitHubからunitypackageをダウンロードしてインポート
    • https://github.com/Cysharp/UniTask/releases
    • AssetStoreにはまだ公開されていない

    View full-size slide

  14. UniTaskが使える条件
    • C# 7以降が使えるUnityであること
    • Unity 2018.3 以降
    • Unity 2018.2 以前はIncremental Compilerを導⼊していると使える

    View full-size slide

  15. UniTaskの機能紹介

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. UniTask型/UniTask型
    UniTaskの機能紹介

    View full-size slide

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

    View full-size slide

  20. Task型 vs UniTask型
    Task UniTask
    機能 Unityでは不要な機能が多い Unityで活⽤できる機能のみ
    オブジェクトサイズ ムダに⼤きい ⼩さい
    実⾏コンテキスト管理
    TaskScheduler &
    SynchronizationContext
    PlayerLoop
    必要なC# version C# 5.0以上 C# 7.0以上
    Task Tracker 無 Unity Editor上で利⽤可能

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  28. UniTaskCompletionSource

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  41. UniTask.Yield

    View full-size slide

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

    View full-size slide

  43. UniTask.SwitchToThreadPool

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  46. UniTask.WaitUntil / UniTask.WaitWhile

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  49. UniTask.WhenAll

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  53. Awaiter
    UniTaskの機能紹介

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  59. コルーチンのAwaiter

    View full-size slide

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

    View full-size slide

  61. AsyncOperationのAwaiter

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  67. UniTaskTracker
    UniTaskの機能紹介

    View full-size slide

  68. UniTaskTracker
    • await中のUniTaskを可視化するEditor拡張
    • Unity Editorの [Window] -> [UniRx] -> [UniTask Tracker]
    • UniTaskがリークしていないか確認できる

    View full-size slide

  69. UniTaskとキャンセル

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  75. CancellationToken

    View full-size slide

  76. CancellationToken
    CanellationTokenSourceから⽣成

    View full-size slide

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

    View full-size slide

  78. 補⾜: GetCancellationTokenOnDestroy()

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  91. 最後のまとめ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  94. まとめ
    • UniTaskめっちゃ便利だから使おう!!!!
    • あと今回の話の補⾜的なのをUniBook11に書きました
    • さらにUniRx+UniTask本、マダカイテルカラマッテネ…

    View full-size slide