初めに
Unity 2023.1 から公式でAwaitableという非同期向けのクラスが用意されました。
今回はこれを使うにあたりUnityのAPI使えない問題に遭遇したので対処のメモです。
先に結論
Awaitable.MainThreadAsync
を使ってメインスレッドでUnityのAPIを使い、
Awaitable.MainThreadAsync
を使ってバックグラウンドスレッドで処理を行う
参考: https://docs.unity3d.com/2023.2/Documentation/Manual/AwaitSupport.html
遭遇した事象
例えば以下のコードだと2か所でその処理、バックグラウンドスレッドで処理できないよ
と怒られます。
await Task.Delay(0); // ここでは他の非同期処理 (Delay()で代用)
// 画像を作成して保存したい
var imagePath = Path.Combine(Application.persistentDataPath, fileName); // ここでNG ・・・1
var texture = new Texture2D();
await File.WriteAllBytesAsync(imagePath, texture.EncodeToPNG()); // ここでNG ・・・2
なぜ怒られるかというと、1つ目はApplication.persistentDataPath
が、2つ目はtexture.EncodeToPNG()
がそれぞれ怒られてしまいます。
文字列の取得だけに怒られるなんて...
エンコードなんていう重い処理をバックグラウンドスレッドで実行させてくれないなんて...
対策
さて、ファイル書き込みを含む重めになりそうな処理をするのであれば非同期にはしたいです。
ドキュメントをあさってみるとUnity 2023.2以降のEnglishページに解決策が書いてありました。
結論の通りに修正すると以下のコードになります。
await Task.Delay(0); // ここでは他の非同期処理 (Delay()で代用)
// 画像を作成して保存したい
await Awaitable.MainThreadAsync(); // UnityのAPIをメインスレッドで実行する
var imagePath = Path.Combine(Application.persistentDataPath, fileName);
var texture = new Texture2D();
var pngData = texture.EncodeToPNG();
await Awaitable.BackgroundThreadAsync(); // ファイル書き込みはバックグラウンドスレッドで実行する
await File.WriteAllBytesAsync(imagePath, pngData);
これで問題なく動くようになりました!
ポイントとしては
- バックグラウンドで処理したい場合は
await Awaitable.BackgroundThreadAsync()
する - メインスレッドで処理したい場合は
await Awaitable.MainThreadAsync()
する 2024/2/28現在は2023.2以降の英語マニュアルでないとAwaitableの解説がない
というところですね。
最後に
それメインスレッドでなくても・・・と思うところはありましたが、基本的に非同期は複雑性と危険性が伴うのも事実なのでマニュアルに沿ってメインスレッドとバックグラウンドスレッドを切り替えていけばよさそうですね!