7.1K Views
October 25, 22
スライド概要
非同期プログラミングを分かりやすく効率的に記述する手法としてasync/awaitがC#に登場して10年。UnityにUniTaskが登場して4年。今年にはUnityランタイムの近代化としてasync/awaitプログラミングモデルの改善について公式から言及がありました。また、C#におけるasync/await自体も言語機能の進化と共に変化しています。今こそ改めて、Unityとasync/awaitの現状と、UniTaskの実装をもとに、その詳細と使うべき理由、効率的に使いこなす手法を解説します。
こんな人におすすめ:
・非同期処理を極めたいエンジニア
・C#の詳細に踏み込みたい人
受講者が得られる知見:
・async/awaitとコルーチンの違い
・async/awaitやUniTaskの実装の詳細
・async/awaitやUniTaskの効率的な利用方法
出演:
河合 宜文 (Cysharp)
--
初出: SYNC 2022 #UnitySYNC
https://events.unity3d.jp/sync/
リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。
河合 宜文 / Kawai Yoshifumi / @neuecc Cysharp, Inc. Cygames C#大統一理論 C# UniTask
Unity用の高機能/高性能 async/awaitライブラリ https://github.com/Cysharp/UniTask 4K
話すこと 話さないこと
登場以来、言語と合わせて進化し続けている
https://blog.unity.com/ja/technology/unity-and-net-whats-next
async/awaitはマルチスレッドではない PlayerLoopもasync/awaitもカスタマイズできる
同期処理でできることが出来ない
static string GetSync(int page)
{
try
{
var url = "http://...?page=" + page;
var html = GetHttpStringSync(url);
return html;
}
catch
{
throw;
}
}
static IEnumerator GetAsync(int page,
Action<string> onCompleted,
Action<Exception> onError)
{
try
{
var url = "http://...?page=" + page;
var response = GetHttpStringSync(url);
yield return response;
onCompleted(response);
}
catch(Exception ex)
{
onError(ex);
}
同期処理でできることが出来ない
static string GetSync(int page)
{
try
{
var url = "http://...?page=" + page;
var html = GetHttpStringSync(url);
return html;
}
catch
{
throw;
}
}
static IEnumerator GetAsync(int page,
Action<string> onCompleted,
Action<Exception> onError)
{
try
{
var url = "http://...?page=" + page;
var response = GetHttpStringSync(url);
yield return response;
onCompleted(response);
}
catch(Exception ex)
{
onError(ex);
}
非同期を同期的に扱う仕組み
static string GetSync(int page)
{
try
{
var url = "http://...?page=" + page;
var html = GetHttpStringSync(url);
return html;
}
catch
{
throw;
}
}
static async Task<string> GetAsync(int page)
{
try
{
var url = "http://...?page=" + page;
var html = await GetHttpStringAsync(url);
return html;
}
catch
{
throw;
}
}
コルーチンでできることが出来ない
IEnumerator CoroutineCode()
{
yield return new WaitForFixedUpdate();
yield return new WaitForSecondsRealtime(1.0f);
yield return new WaitForSeconds(1.0f);
yield return new WaitUntil(() => waiting);
var req = UnityWebRequest.Get("http://foo")
.SendWebRequest();
yield return req;
var text = req.webRequest.downloadHandler.text;
}
async Task TaskCode()
{
// WaitForFixedUpdate 相当は無理
await Task.Delay(TimeSpan.FromSeconds
// timeScaleに影響されるDelayは無理
// WaitUntil相当はない
// AsyncOperationは素のままだと
// awaitできない
}
コルーチンでできることが全て出来る
IEnumerator CoroutineCode()
{
yield return new WaitForFixedUpdate();
yield return new WaitForSecondsRealtime(1.0f);
yield return new WaitForSeconds(1.0f);
yield return new WaitUntil(() => waiting);
var req = UnityWebRequest.Get("http://foo")
.SendWebRequest();
yield return req;
var text = req.webRequest.downloadHandler.text;
}
async UniTask UniTaskCode()
{
await UniTask.WaitForFixedUpdate();
await UniTask.Delay(1000,UnscaledDeltaT
await UniTask.Delay(1000,DeltaTime);
await UniTask.WaitUntil(() => waiting);
var req = await UnityWebRequest.Get("ht
.SendWebRequest();
var text = req.downloadHandler.text;
}
コルーチンでは想像しなかったことまで出来る
見た目や正常系は同期と一緒になった、が?
static string GetSync(int page)
{
try
{
var url = "http://...?page=" + page;
var html = GetHttpStringSync(url);
return html;
}
catch
{
throw;
}
}
static async UniTask<string> GetAsync(int page)
{
try
{
var url = "http://...?page=" + page;
var html = await GetHttpStringAsync(url);
return html;
}
catch
{
throw;
}
}
見た目や正常系は同期と一緒になった、が?
static string GetSync(int page)
{
try
{
var url = "http://...?page=" + page;
var html = GetHttpStringSync(url);
return html;
}
catch
{
throw;
}
}
static async UniTask<string> GetAsync(int page)
{
try
{
var url = "http://...?page=" + page;
var html = await GetHttpStringAsync(url);
return html;
}
catch
{
throw;
}
}
伝搬(型が非同期を表現すること)は悪くない キャンセル処理は定型パターン https://neue.cc/2022/07/13_Cancellation.html
Conclusion
言語の進化から降りない オーパーツを手に