simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

Unity:別スレッドで重い処理(AI処理とか、画像処理とか)

Unity でビジュアライズしている何かしらのアルゴリズム(AIとか画像処理とか)について、処理中にUIが固まることはユーザービリティの面から看過できません。

Unity 2017 になってから、C# 5.0 からの新機能 Task(async/await) が使えるようになりました。
これを使うだけです。

ただ使うには、PlayerSettingsをExperimental(実験的な設定)に変更する必要があります。私は次の記事を参考に変更しました。
qiita.com

具体的なコードとしては

await Task.Run 以降のラムダ式をメインスレッドとは別のスレッドにて非同期実行させることができます。
await キーワードは async キーワードを付けた関数の中でなければ、記述できません。

ということで、以下のようなコードで重い処理を別スレッドで書き、結果が出たらスレッドアンセーフでゲームオブジェクトへ適用することができるようになります。

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

public class ThreadTaskTestBehaviour : MonoBehaviour
{
    void Start()
    {
        this.MoveAsync();
    }

    private async void MoveAsync()
    {
        var context = SynchronizationContext.Current;
        await Task.Run(() =>
        {
            for (int i = 0; i < 10000; i++)
            {
                if (9999 == i)
                {
                    Vector3 position = Vector3.zero;
                    Debug.Log("i = " + i);
                    context.Post((state) =>
                    {
                        position = this.transform.localPosition;
                        Debug.Log("position.x = " + position.x);
                        position.x -= i * 0.01f;
                        this.transform.localPosition = position;
                        Debug.Log("in post position.x = " + position.x);
                    }, null);
                    Debug.Log("out of post position.x = " + position.x);
                }
            }
        });
    }
}

以下、参考にした記事
Unityでのマルチスレッド処理はみなさんの関心事なんだなって思います。

ただ、2018年中ごろには、Unityが、同じ処理を大量に並列処理するC# Jobs System を入れてくるらしいので、いずれはそれを使うことになるかも?

www.slideshare.net
しかし、単一の重い処理をバックグラウンドで実行する処理は、ひとまず今回の記事のやり方で問題なく対応できます。

techblog.kayac.com
tyheeeee.hateblo.jp
satoshi-maemoto.hatenablog.com
qiita.com
qiita.com