Unity - Package - UniTask
前述
UniTask - Unity 中實現效能最好的 async/await 的函式庫
Unity 中預設的非同步實現是 - Coroutine 協程,但協程有以下缺點
- 無法使用回傳值,需使用 callback 來解決。
- 異常處理很困難,因為不能在 try-catch 區塊內使用 yield。
- 需透過 MonoBehaviour.StartCoroutine 才能啟動。
UniTask 相較於 C# 原生的 Task 做了以下改進
- 刪除了 Task 在 Unity 不需要的功能。
- 非 MonoBehaviour 裡也能實現非同步。
- 記憶體/ GC / Unity PlayerLoop 等方面做最佳化。
- UniTaskTracker 提供編輯器上可視化追蹤 await 狀態,這對於檢查是否有洩漏很有用。
UniTask 官方文件的基本功能寫得相當清楚,並附上一些入門介紹
以下紀錄幾個重點主題
Awaiter
UniTask 已經實作了相當豐富的 Awaiter 擴充,有需要自訂的可以參考以下規範
Thread
- UniTask.SwitchToThreadPool 允許後續處理在執行緒池中進行。
- UniTask.SwitchToMainThread 切換到主執行緒,不會等待下一幀。
- 也可以使用 UniTask.Yield 切換到主執行緒,但它總是等待一幀。
但目前尚未有使用到的情境,之後有遇到再嘗試。
此外使用執行緒池,將無法與 WebGL 等平台相容。未來應該也會避開使用。
Cancellation
Cancel 算是在使用 Task-based 機制時最須留意的事項。UniTask 一旦被取消,且還在 await 的話,那麼 await 後面的程式碼就不會被執行。因此盡可能將 CancellationToken 傳遞給非同步方法。如果不能傳遞,則手動判斷。
private async UniTask<string> ReadTxtAsync(string path, CancellationToken token)
{
return await UniTask.Run(() =>
{
// 執行前檢查
token.ThrowIfCancellationRequested();
var str = File.ReadAllText(path);
// 執行後檢查
token.ThrowIfCancellationRequested();
return str;
});
}
當 Cancel 跟 MonoBehaviour OnDestroy 時機掛勾時,能透過 GetCancellationTokenOnDestroy 來取得對應的 CancellationToken。
在 WebGL 這種對性能要求比較高的情境,建議使用 SuppressCancellationThrow 函數,来避免 OperationCanceledException 抛出。
這裡有詳細探討與建議作法
Completion
- 【UniTask】UniTaskCompletionSourceを使って好きなタイミングで結果を確定させるUniTaskを生成する(ついでにUniTask.Voidの紹介)
- Cancel a CompletionSource with a cancellation
Timeout
- 建議使用 TimeoutController
- 不要忘記與現有的結合 CancellationToken
- 避免使用 AttachExternalCancellation
Extra
Unity 官方也將在 Unity 2023.1 之後逐步完善 async/await 機制