Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
.NETの非同期戦略とUnityとの相互運用
Search
Yoshifumi Kawai
March 21, 2024
Technology
56k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
.NETの非同期戦略とUnityとの相互運用
Game Developers Meeting Vol.61
GDM × Born Digital
Yoshifumi Kawai
March 21, 2024
More Decks by Yoshifumi Kawai
See All by Yoshifumi Kawai
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
5.2k
.NET for Android with Native AOT Built with Cursor
neuecc
0
8k
CysharpのOSS群から見るModern C#の現在地
neuecc
2
48k
R3のコードから見る実践LINQ実装最適化・コンカレントプログラミング実例
neuecc
5
57k
他言語がメインの場合のRustの活用法 - csbindgenによるC# x Rust FFI実践事例
neuecc
7
42k
Modern High Performance C# 2023 Edition
neuecc
4
16k
CEDEC 2023 モダンハイパフォーマンスC# 2023 Edition
neuecc
9
120k
C#11 による世界最速バイナリシリアライザー「MemoryPack」の作り方
neuecc
1
43k
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
neuecc
1
540
Other Decks in Technology
See All in Technology
パッチ更新でterraform initが落ちた日
grimoh
1
140
Local CI × GitHub Actions
gogutan
3
230
AIにシークレットを見せない、WSL2で安全な開発環境
yazm
0
310
OptunaHub: ブラックボックス最適化のためのプラットフォーム
pfn
PRO
0
140
Conditional PED-ANOVA: Hyperparameter Importance in Hierarchical & Dynamic Search Spaces
pfn
PRO
0
140
Code for Security プロジェクト紹介 2026年10月
yu23ki14
0
110
[JAWS-UG彩の国埼玉#12]そろそろ準備する?re:Invent2026をやさしく解説 / reinvent2026-sainokuni
sh_fk2
1
360
日本語に強いオープンな大規模言語モデル「LLM-jp」
odashi
5
1.2k
AI コーディングと人間の認知スループット / CTO Night & Day 2026 Morning Session / AI Coding and Human Cognitive Throughput
prog893
5
1.3k
触りたくないデータに、どう触るか AI時代のRBACアクセスガバナンス
ivry_presentationmaterials
0
280
PagerDuty Tech Hub-鳴らすけれど、人は動かない
ezaki
0
180
エンタメ企業のM&Aを支えるデータ基盤 ― 統合から店舗のリアルタイム分析まで / Data Engineering Summit 2026
genda
0
200
Featured
See All Featured
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
4
4.4k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
46k
A better future with KSS
kneath
240
18k
A Soul's Torment
seathinner
8
3.8k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
710
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
450
Facilitating Awesome Meetings
lara
57
7.2k
Crafting Experiences
bethany
1
380
Un-Boring Meetings
codingconduct
0
460
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.6k
Heart Work Chapter 1 - Part 1
lfama
PRO
10
37k
Transcript
.NETの非同期戦略とUnityとの相互運用 Game Developers Meeting Vol.61 GDM x Born Digital 2024-03-21
Yoshifumi Kawai / Cysharp, Inc.
About Speaker 河合 宜文 / Kawai Yoshifumi / @neuecc Cysharp,
Inc. - CEO/CTO 株式会社Cygamesの子会社として2018年9月設立 C#関連の研究開発/OSS/コンサルティングを行う Microsoft MVP for Developer Technologies(C#) since 2011 CEDEC AWARDS 2022エンジニアリング部門優秀賞 .NETのクラスライブラリ設計 改訂新版 監訳 50以上のOSSライブラリ開発(UniRx, UniTask, MessagePack C#, etc...) C#では世界でもトップレベルのGitHub Star(合計30000+)を獲得
最近のOSS R3 - The new future of dotnet/reactive and UniRx
https://github.com/Cysharp/R3/ Unity使いの人に一言でいえば、UniRx2 UniTaskなどasync/awaitとの共存を意識して現代的に再設計 ObsevableTrackerというリーク確認ウィンドウ付きで便利 Claudia - Unofficial Anthropic Claude API client for .NET. https://github.com/Cysharp/Claudia UnityでもRuntime/Editorともに動きます! EditorでAIを活用したワークフロー改善 Runtimeで直接的なAIゲームを作ったりできます! 超レコメンデッド
Two Decades of Asynchronous Programming in C#
.NET Unity async/await Coroutine Rx UniRx UniTask Awaitable Channel ValueTask
EAP TAP APM APM = Asynchronous Programming Model(Begin/End) EAP = Event-based Asynchronous Pattern TAP = Task-based Asynchronous Pattern Rx = Reactive Extensions IAsyncEnumerable TPL Dataflow R3 C#誕生初期(2000年)から現在(2024年) までの24年間の非同期処理 TPL(Parallel) ThreadPool C# Job System
.NET Unity async/await Coroutine Rx UniRx UniTask Awaitable Channel ValueTask
EAP TAP APM IAsyncEnumerable TPL Dataflow R3 初期に構築されたものはさようなら TPL(Parallel) ThreadPool C# Job System
.NET Unity async/await Coroutine Rx UniRx UniTask Awaitable Channel ValueTask
EAP TAP APM IAsyncEnumerable TPL Dataflow R3 TPL(Parallel) ThreadPool C# Job System IValueTaskSource(.NET Standard 2.1), PoolingAsyncValueTaskMethodBuilder(.NET 6)などの強化 IThreadPoolWorkItem(.NET Core 3.0)の追加 フルManaged(C#)実装化(.NET 6)などの強化 Parallel.ForEachAsync(.NET 6) Parallel.ForAsync(.NET 8)の追加 生存してるものは折々強化さ れています!
.NET Unity async/await Coroutine Rx UniRx UniTask Awaitable Channel ValueTask
EAP TAP APM IAsyncEnumerable TPL Dataflow R3 UniTask, Awaitableは共存(むしろどち らかというとUniTaskメインに使う) 詳しくはUnityプログラミング・バイ ブル R6号に執筆したので読もう! TPL(Parallel) ThreadPool
.NET Unity async/await Coroutine Rx UniRx UniTask Awaitable Channel ValueTask
EAP TAP APM IAsyncEnumerable TPL Dataflow R3 TPL(Parallel) ThreadPool go to R3; C# Job System
.NET Unity async/await Coroutine Rx UniRx UniTask Awaitable Channel ValueTask
EAP TAP APM IAsyncEnumerable TPL Dataflow R3 TPL(Parallel) ThreadPool C# Job System Unityで使いたい場合、NuGet経由で入れる or UniTaskに簡易化したChannelがあります
NuGet in Unity
NuGetをUnityで使う 標準ライブラリが使えるシチュエーションの増加 Unityの.NET Standard 2.1準拠によって使えるライブラリが増えた Source Generatorも動作(Unity 2022.3.12f1以降ならRoslyn 4.3.0まで行ける) IL2CPP時のリフレクション・WebGL利用時のThreadPool利用など
を回避できれば、多くのライブラリが動作する 依存の解決 Managed DLL同士の依存関係を素直に解決するならNuGetに頼っ たほうがいいし、.NET x Unityで共通化していく際に実体が別物 (MessagePack-CSharpなど)だとかなり不便 .NETが近年NativeAOTの強化につき、リ フレクション利用に気を使いだしてきて、 結果としてIL2CPPでも問題なく動作する ようになってきた 最近のCysharpライブラリは NuGet化を推し進めています
NuGetをUnityで使う NuGetForUnity https://github.com/GlitchEnzo/NuGetForUnity シンプルにNuGetサーバーからDLLを落としてくるエディタ拡張 挙動が分かりやすくて良い。ただし、コードがコンパイルできな い時にはエディタ拡張も動かない→DLLが落とせない→一生コンパ イルできない、などの拡張ゆえのはまりどころもある UnityNuGet https://github.com/xoofx/UnityNuGet UnityのPackage
Managerの追加レジストリとして動作する UPMとして自然な挙動、ただしDLL配布サーバーは独自サーバー Cysharp的にはこちらを薦めています OpenUPMと合わせたりでこちらのほ うが扱いやすい、という意見もあり
Task/ValueTaskとThreadPool .NETとUnityの共通非同期インターフェイス UniTaskやAwaitableはUnity専用 .NETと共通で非同期処理を実装するならTask/ValueTaskで表す ThreadPool行きを避ける Unityの提供する非同期メソッドは完了時にエンジン側でメインス レッドに戻してくれる(AsyncOperationなど) 不要なオーバーヘッドが発生しているかもしれない うっかりThreadPool内に入るとUnityのAPIが呼べない! そしてWebGLで動作しない
UniTaskを使えば何も考えなくてもいい(最高!)けれど、 Task/ValueTaskを使わなければいけないなら……?
Continue on ThreadPool 1 async void Start() { // SynchronizationContext.SetSynchronizationContext(null);
var tcs = new TaskCompletionSource<object>(); StartCoroutine(NextFrame(tcs)); await tcs.Task; Debug.Log(Thread.CurrentThread.IsThreadPoolThread); } IEnumerator NextFrame(TaskCompletionSource<object> tcs) { yield return null; ThreadPool.QueueUserWorkItem(_ => tcs.TrySetResult(null)); } False ThreadPool上で継続を流す場合 UnityはデフォルトでUnitySynchronizationContextがセット されていて、await時にUnityのメインスレッドに戻す
Continue on ThreadPool 2 async void Start() { SynchronizationContext.SetSynchronizationContext(null); var
tcs = new TaskCompletionSource<object>(); StartCoroutine(NextFrame(tcs)); await tcs.Task; Debug.Log(Thread.CurrentThread.IsThreadPoolThread); } IEnumerator NextFrame(TaskCompletionSource<object> tcs) { yield return null; ThreadPool.QueueUserWorkItem(_ => tcs.TrySetResult(null)); } True メインスレッドに戻す機構がな いのでThreadPool上のまま UnitySynchronizationContextがセットされていない場合
ConfigureAwait : (unity-context | true) async void Start() { //
SynchronizationContext.SetSynchronizationContext(null); var tcs = new TaskCompletionSource<object>(); StartCoroutine(NextFrame(tcs)); await tcs.Task; // .ConfigureAwait(false); Debug.Log(Thread.CurrentThread.IsThreadPoolThread); } IEnumerator NextFrame(TaskCompletionSource<object> tcs) { yield return null; tcs.TrySetResult(null); } False このケースでは実は UnitySynchronizationContextは「使われ ていないの」でSynchronizationContextの パフォーマンス上のペナルティはない Unityのメインスレッド内でTaskの継続を呼ぶ
ConfigureAwait : (null-sync | true) async void Start() { SynchronizationContext.SetSynchronizationContext(null);
var tcs = new TaskCompletionSource<object>(); StartCoroutine(NextFrame(tcs)); await tcs.Task; // .ConfigureAwait(false); Debug.Log(Thread.CurrentThread.IsThreadPoolThread); } IEnumerator NextFrame(TaskCompletionSource<object> tcs) { yield return null; tcs.TrySetResult(null); } False nullをセットしてもThreadPoolにはいかない、というのも コルーチンがPlayerLoop上でTaskを継続させているので
ConfigureAwait : (unity-context | false) async void Start() { //
SynchronizationContext.SetSynchronizationContext(null); var tcs = new TaskCompletionSource<object>(); StartCoroutine(NextFrame(tcs)); await tcs.Task.ConfigureAwait(false); Debug.Log(Thread.CurrentThread.IsThreadPoolThread); } IEnumerator NextFrame(TaskCompletionSource<object> tcs) { yield return null; tcs.TrySetResult(null); } True メインスレッド上でTaskを継続させていても ConfigureAwait(false)によってThreadPool行き
ConfigureAwait : (null-sync | false) async void Start() { SynchronizationContext.SetSynchronizationContext(null);
var tcs = new TaskCompletionSource<object>(); StartCoroutine(NextFrame(tcs)); await tcs.Task.ConfigureAwait(false); Debug.Log(Thread.CurrentThread.IsThreadPoolThread); } IEnumerator NextFrame(TaskCompletionSource<object> tcs) { yield return null; tcs.TrySetResult(null); } True Synchronization Contextの有無は関係ない ConfigureAwait(false)によってThreadPoolへ行く
Task/ValueTaskのThreadPool行き条件 Task.Run ある意味、明示的なThreadPool行き JobSystemほど制限がないため、CPUを使った並列処理をカジュアル に行いたいときには便利 TaskCompletionOptions.RunContinuationAsynchronously TaskCompletionSourceのTrySetResult時に、trueで必ずThreadPool行 きするオプション。ネットワーク系ライブラリでよくある。Channel ではOptions {
AllowSynchronousContinuations } の意味が、これをど ちらに設定するかということをさす。falseにすると (RunContinuationAsynchronouslyと逆)場合によりThreadPool行きする
Task/ValueTaskのThreadPool行き条件 ConfigureAwait(false) 問答無用でThreadPoolに飛ばすの意(ThreadPool上での継続の場合 はほとんどの場合、そのままそのスレッドのまま処理する) .NETのasync/awaitのプラクティスとして「ライブラリのasyncメソッ ドはConfigureAwait(false)を使うこと」というのがあり、場合によっ て(あるいはほとんどの場合)Unity側から避ける術がない なお、ConfigureAwaitを使わない場合でも、SynchronizationContext は常に使われるわけではなく、SynchronizationContextが同一の場合、 Unityの場合でいうとメインスレッド上で継続される場合はインライ
ンで処理されていくので、UnitySynchronizationContextのオーバー ヘッドは発生しないようになっている。
Task/ValueTaskのThreadPool行き条件 ConfigureAwait(false) 問答無用でThreadPoolに飛ばすの意(ThreadPool上での継続の場合 はほとんどの場合、そのままそのスレッドのまま処理する) .NETのasync/awaitのプラクティスとして「ライブラリのasyncメソッ ドはConfigureAwait(false)を使うこと」というのがあり、場合によっ て(あるいはほとんどの場合)Unity側から避ける術がない なお、ConfigureAwaitを使わない場合でも、SynchronizationContext は常に使われるわけではなく、SynchronizationContextが同一の場合、 Unityの場合でいうとメインスレッド上で継続される場合はインライ
ンで処理されていくので、UnitySynchronizationContextのオーバー ヘッドは発生しないようになっている。 なお、UniTaskはこういった面倒ごとが絶対に発生しないよ うにConfigureAwaitというシステムそのものを排除している 非同期処理を含むNuGetライブラリをUnity WebGL対応も考 慮して作るのはめちゃくちゃ大変……、という教訓をR3の実 装で得ました(R3はきっちり全回避してWebGL対応です!) この「ライブラリはConfigureAwait(false)必須」プラクティス、現代 では不要説もある。昔、ASP.NETにSyncContextがあった&非同期対 応が不十分のためしょうがなく .Resultしたらデッドロックしまくっ た、のを回避するため生まれたプラクティスなので(現在は ASP.NETはSyncContextはない(ただしBlazorにはある)&フレームワー クが完全に非同期を考慮しているので.Resultすることもないため)
None