Skip to content

「Unity 非同期完全に理解した勉強会」に参加したよという話

Posted in 技術記事/勉強会

2018年9月15日「Unity 非同期完全に理解した勉強会」というイベントに参加してきたので、その備忘録です。

概要

某プテピピックで出てきた「完全に理解した(わかってない)」というフレーズを冠したイベントの3回目です。今回の主催はとりすーぷさんですが、運営は毎度おなじみもんりぃ先生青木ととさんが主に担当しています。
なんと休憩込みで5時間に及ぶセッションが用意されてたり、MVPを取った豪華登壇者がズラッと並んだり、本当にユーザーイベントか疑わしいレベルでした。(まあUTJの中の人もめっちゃ噛んでますが)
会場は銀座にある「NIFcLounge(ニフクラウンジ)」です。富士通のグループ会社、富士通クラウドテクノロジーズ株式会社さんのオフィスです。IT関連の勉強会には無料で貸出をしているようなので、主催者の方は利用を検討してみてはいかがでしょうか。ちなみにこの会場、今回は定員170名でしたが、パーティションで区切って10人程度?からでも利用できるようです。
またニフクラはクラウドサービスで、Unity向けのサービスもあるのでお世話になってる方もいるのではないでしょうか。かくいう自分も利用しています。(少し古いですが過去記事

ライブ配信

ニコ生タイムシフト
2018年9月22日まで閲覧可能。後日、録画したものをYoutubeにアップするそうです。

「Deep Dive async/await in Unity」

河合 宜文さん Twitter: @neuecc
資料

Rxについて

Rxは時間軸で解釈してなんでも統一的に扱えるのが強みであり弱み

  • For,try-catchは見た目通りかけない→書かないほうがいい
  • 非同期はasync/awaitの方が適役
  • Rxはイベントストリームを活用する

async/awaitについて

async/awaitはマルチスレッドではない!!!!
なっちゃうことも稀によくある、という話

Taskが持つ悲しみの歴史

  • Taskにasync/awaitを乗っけて実装したため、イケてない部分が多く残った
  • UnityはC#のアプデが遅れたためそこをスキップできる
  • そのためのUniTask(C#ではValueTask)

async/awaitの動作

Awaitは自動的にそこでぶった切ってコールバックになるイメージ
非同期処理を書いても非同期じゃないときもある
例:キャッシュ機構→初回は必ず非同期だが、次からはキャッシュを同期処理で呼ぶ
おかげでパフォーマンスがよい
asyncメソッドのなかにawaitがいくつあっても内部で冗長にならない→まとめた方が効率がよい

UniTask

UniTaskはC#7(unity2018.3)の機能を使った、Unity専用フレームワークで、以下のような点を理由に作られた

  • Unityは基本シングルスレッドなのでTaskは実はいらない
  • async/awaitはTaskのおかげで(意図せず)マルチスレッド動作をしてしまう
  • マルチスレッドを考慮しなければ効率が上がるのでは?

?WebGLはマルチスレッドが使えないので、unityroomで引っかかるのはこのへんのせいかも

機能色々

UniTaskはコルーチンを代替出来る(高速軽量な!)処理がある
実はJobSystemもawait出来る

async/awaitのキャンセル

キャンセルが面倒
→ひたすらcancellationtokenが伝搬する、めんどい(が、そうするしかない
キャンセルがある前提だとやばい
OnDestroyで処理するのが便利

AsyncEventhandling

Eventをasync/awaitで実装できる
→でもRx(ReactivePropaty)のほうが基本よい

まとめ

性能も手法も問題ない、すぐにでも使い始めたほうがよい

おまけ

C#最速シリアライザ

「async/await のしくみ」

岩永信之さん Twitter: @ufcpp

資料

最新版のUnityでC#7.2が使えるよ(C#の最新は7.3だよ!…あれ?)

非同期とは

  • 同時実行
    •  CPUの処理を奪い合う
    • UIスレッド=Unityではメインスレッドとよばれる
      • ユーザの入力の受付をする。描画もされる
      • ここを重用するとフリーズしたりする。UXがさがる
  • 並列実行
    • 複数CPUをつかう
  • IO待ち
    • CPUとそれ以外のやりとりの待ち時間(数桁レベルで速度が違う)
      • awaitの使い所
      • ユーザー入力受け取り後の処理 メインスレッドを止めない

C#標準の非同期処理

  • Thread
    • OSの強権をつかうので重い、使うことはそうない
  • ThreadPool
    • 事前にスレッドを立てて分配
    • こちらも低レイヤーなので使うことは少ない
  • Task
    • 非同期処理の続きを書けるクラス=コールバック
    • コールバックがめんどう
  • await
    • Task(のコールバック)を便利にした
    • UnityGCの性能は低い

async/await

同期っぽいコードから非同期コードを生成してくれる

その他

ValueTaskはいつから使える?→割と古いバージョンから使える

「実践! ライブコーディングで覚えるasync/await」

細田幸治さん 株式会社オレンジキューブ所属 FaceBook : kouji.hosoda
資料(内容は動画アーカイブを参照)

For文の中でもawaitで待てる
→ユーザーの入力待ち(ページ送りとか)に便利

タプル→C#7「名前のない型」を作る機能

メンバーが増えたら(4つとか)独自クラスを作ろう

splitは結構重いので(非同期で)先に処理したほうがよい

Try-chatch
→必ず行われるべき処理はfinallyに書く

ラムダ式はエラーの場所がわかりにくいので中身を増やしすぎないこと

先にロードしてあとからawaitする
→awaitのタイミングですでにロードが完了してる場合、非同期しない処理として最適化される。えらい。

同期(直列)で書きたいけど非同期にせざるを得ない場所でawaitが便利

「はたらくスレッド」

名雪 通さん & 安原 祐二さん Twitter: @tnayuki ユニティ・テクノロジーズ・ジャパン所属
資料

このセッション、是非動画でみて欲しい
安原さんと名雪さんの小芝居がとても面白かったです(笑)

「Observableの非同期処理への活用」

とりすーぷさん Twitter: @toRisouP
資料

非同期処理とは?

結果を待たないで次に行く
マルチスレッドとは限らない
結果の扱い、エラーハンドリング、キャンセル、etc考慮することが多く難しい

Unityで使えるやつ

  • Unityコルーチン
  • C# async/await
  • UniRx(observable)
  • UniRx(Async)
  • 独自実装

使いやすさ

async/await > UniRx

本題

UniRxは「イベント処理ライブラリ」だけではなく「非同期処理」にも使える

Observable

Observable=ストリーム
イベント処理に強い、ゲームはイベントが多い→ゲーム作りで便利

イベント処理と非同期処理

イベント処理→メッセージ数が不定 OnTriggerとかそのへん
非同期処理→メッセージ数が必ず1つ
Observableで同じように処理できる

コルーチンと比較

Observableで包むと使いやすくなる、後からでもOK
実行結果→IObservable<T>で扱える
直列処理→.ContinueWithで繋げれば非同期で待てる
並行処理→Observable.WhenAllで包めばOK

UniRxの多様なエラーハンドリングOperator

  • Catch 差し替える(任意)
  • CatchIgnore 差し替える(Empty)
  • Retry やり直す、使い所に注意
  • OnErrorRetry Catch+Retry
  • Timeout

AsyncSubject

非同期処理をするためのSubject

  • メッセージを1つだけキャッシュ
  • あとからsubscribeしても結果をとれる
  • async/awaitで待てる

用途

  • 非同期処理の通知
  • コンポーネント初期化順序
    • 初期化=非同期処理が連鎖する、と捉えて書き換える

PublishLast()

Hot変換するOperator

  • Cold→subscribeする前の(動いてない)Observable
  • Hot→subscribeした(動いてる)Observable
  • LinQと似たような性質

Hot変換=1度Subscribe()する=LinQを1回実行してlistに詰め直す

仲間

  • Publish()
  • Publis(T initValue)
  • PublisLast()
  • Replay()

メリット→Observableを先に実行できる&結果をキャッシュできる
デメリット→失敗もキャッシュする=エラーハンドリングが不可能になる

Observable.Start()

Task.Runとほぼ同じ
同期処理を簡単にマルチスレッドの非同期処理にできる

Observable.Create()

自前のObservableをつくれる
使い方は無限大
既存の非同期処理をラップできたりする、便利
→ニフクラSDKをObservable化、など
そのまま使うとメインスレッドをブロッキングする
→SubscribeOn(Scheduler.ThreadPool)でThreadPoolに移動できる

Observable.FromCoroutine

コルーチンをObservableに変換できる
コルーチンの最大の欠点(結果を取り出せない)が解消できる

ToYieldInstruction

ObservableをIEnumeratorに変換する
コルーチンでasync/awaitぽい処理ができる

Observable.FromCoroutineとToYieldInstructionでasync/awaitが使えない環境でも戦える

まとめ

まずはasync/awaitを使う→処理が難しい場合はObservableで書く
Hot/Coldに要注意!!!
→DoOnSubscribed、Providerやoperatorでチェック

「いまさらだけど確認しておこう Coroutine」

むろほしりょうたさん Twitter: @RyotaMurohoshi
資料

ブログ
#Unity非同期完全に理解した 勉強会でCoroutineについてLTしました

古い環境を使わざるを得ないこともある…
OnTriggerとかもコルーチンにできるよ

「UnmanagedThreadノススメ」

うえしたさん Twitter: @ueshita
資料

「勧めるとは言っていない」

「ソシャゲ開発で非同期処理の活用法」

ろっさむさん Twitter: @4_mio_11
資料 未公開?

Unity4.xで続けざるを得なかった開発の悲しいお話でした

Be First to Comment

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です