Unity2017.1 Async Await

Unity2017のasync/awaitを試してみた。

  • Version: Unity2017.1.0f3
  • OS: Windows, macOS

結果

  • asyncメソッドの中でもUnity系のAPIは触れる模様。
    • 内部的にはUIスレッドで動作している??
  • asyncで無限ループしている場合、Unityの実行が止まれば一緒に止まる
    • ……ように見えるが、実は残っている!?
    • 少し停止が遅れる模様
      • GameObjectが停止後のヒエラルキーに残ってしまった。
      • 停止後に残ったものが動いた場合、Time.realtimeSinceStartupは0スタート
    • ウィンドウ枠を動かしたらasyncメソッドが動き出す
    • → 無限ループする場合、OnDestroyを使用しフラグによる処理が必要
      • じゃないとプレイ終了後に残ってしまう
      • というか、無限ループしないほうがよい。コルーチンにしたほうがよいなど

Unity APIが使えそうなのはうれしいが実際はコルーチンと同様UIスレッド上で直列で動いていたりするんだろうか。

プレイ終了後に残ってしまうのは長時間スリープするものなどはまずそう。

検証過程

試してみたのは下記のコード。

public class AsyncRunner : MonoBehaviour {

    // Use this for initialization
    void Start () {
        StartAsync();
    }

    async Task StartAsync()
    {
        var createCount = 10;
        while (true)
        {
            await Task.Delay(100);

            Debug.Log($"CurrentTime:{Time.realtimeSinceStartup}");

            if (createCount > 0)
            {
                // asyncの中でGameObject作成も可能
                var go = new GameObject($"{createCount:D02}");
                createCount--;
            }
        }
    }
  1. Play開始
  2. 時間の表示とGameObjectの作成が行われる
  3. Play終了(この時点で7個のGameObjectが作成されている)
  4. GameObjectがさらに3つ作成される & Debug.Logが出力(時間は0スタート)
  5. EditorのUIを触るとDebug.Logが再度動き出す(このときはDelayが効かない?)

下記のようにOnDestroyをトリガーに止めてあげると非プレイ時のウィンドウイベントによって処理が動き出すことはなくなる。

それでも停止時に一回分出力されてしまうので、Task.Delayの直後にフラグチェックをもう一回いれると大丈夫そう(処理とタイミングによりますが)

    async Task StartAsync()
    {
        var createCount = 10;
        while (!isDestroyed)
        {
            await Task.Delay(100);

            Debug.Log($"CurrentTime:{Time.realtimeSinceStartup}");

            if (createCount > 0)![Payload Too Large]()

            {
                var go = new GameObject($"{createCount:D02}");
                createCount--;
            }
        }
    }

    private bool isDestroyed;

    private void OnDestroy()
    {
        isDestroyed = true;
    }