つくるの大好き。

つくるのが大好きな人の記録。

Unity2017で async/await を試してみた

Unity2017から正式に .NET4.6 C#6.0 が利用できるようになりました。
もっとスマートにコードを書きたいのに妥協していた人や、HoloLensアプリ開発でUnityEditorとUWPプロジェクトのC#バージョンの違いにビルド時のエラーで気づかされてああんもうってなってた人には待ちに待った機能ではないでしょうか。

f:id:peugeot-106-s16:20170714164455p:plain


C#バージョンの変更方法はこちら。

blogs.unity3d.com

早速コルーチンとasync/awaitの同時利用などを試してみました。

using System.Collections;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    private const int LoopTimes = 500;

    void Start ()
    {
        this.StartCoroutine(this.TestCoroutine());
        //this.TestAsync();
        this.StartCoroutine(this.TestAsyncInCoroutine());
    }
    private IEnumerator TestCoroutine()
    {
        for (var i = 0; i < LoopTimes; i++)
        {
            Debug.Log(" C " + i);
            yield return null;
        }
    }

    private async void TestAsync()
    {
        var context = SynchronizationContext.Current;
        await Task.Run(() => 
        {
            for (var i = 0; i < LoopTimes; i++)
            {
                Debug.Log("A " + i);
                context.Post((state) =>
                {
                    var p = this.transform.localPosition;
                    p.x += 0.1f;
                    this.transform.localPosition = p;
                }, null);
            }
        });
    }

    private IEnumerator TestAsyncInCoroutine()
    {
        this.TestAsync();
        yield break;
    }
}

this.TestAsync(); と this.StartCoroutine(this.TestAsyncInCoroutine()); はコメントで切り替えて使います。
それぞれ通常の async/awit とコルーチンからのasync/awit呼び出しをテストできます。

結果としてはきちんと並行動作が行われています。
コルーチンがフレームレートに依存するのに対して、async/awaitはスレッドなので可能な限り最高速で動いていることもわかりますね。
f:id:peugeot-106-s16:20170714165224p:plain

また、このasync/awaitのテストコードにあるようにSynchronizationContextを利用すれば、メインスレッド側でGameObjectのTransformなど、スレッドアンセーフなUnityのAPIにアクセスすることも可能です。

とても今風になりましたね!
今後積極的に使っていこうと思います。