はじめに
今回はTransform
に対して動作するようなParallelFor job
について取り上げたいと思います。

また用語の整理をさせていただくとこんな感じ。
・ParallelForTransformジョブ
はIJobParallelForTransformインターフェース
を実装するジョブの総称
・ParallelForジョブ
はIJobParallelForインターフェース
を実装する構造体の総称
環境
Unity 2020.3.18f1
Burst 1.2.0-preview.11
Job 0.2.1-preview.3
IJobParallelForTransformを利用
public class ParallelForTransformTest : MonoBehaviour { // TransformにアクセスできるIJobParallelFor // https://docs.unity3d.com/ja/current/ScriptReference/Jobs.IJobParallelForTransform.html private struct MyParallelForTransformJob : IJobParallelForTransform { [ReadOnly] public float time; public void Execute(int index, TransformAccess transform) { var distance = Vector3.Distance(transform.position, Vector3.zero); transform.localPosition += Vector3.up * math.sin(time * 3f + distance * 0.2f); } } [SerializeField] private GameObject prefab; // 対象のTransformの情報を格納しておく // 構造体,ParallelForTransformジョブをスケジュールする際に必要になる private TransformAccessArray _transformAccessArray; private void Start() { // Cubeをたくさん敷き詰める var size = 35; var list = new List<Transform>(); for (var z = -size; z <= size; z++) { for (var x = -size; x <= size; x++) { var cube = Instantiate(prefab); cube.transform.position = new Vector3 (x * 1.1f, 0, z * 1.1f); list.Add(cube.transform); } } Debug.Log("Cube Count : " + list.Count); // https://docs.unity3d.com/ja/2018.4/ScriptReference/Jobs.TransformAccessArray.html _transformAccessArray = new TransformAccessArray(list.ToArray()); } private void OnDestroy() { _transformAccessArray.Dispose(); } private void Update() { var job = new MyParallelForTransformJob { time = Time.time, }; // ジョブをスケジュールする // https://stephenhodgson.github.io/UnityCsReference/api/UnityEngine.Jobs.IJobParallelForTransformExtensions.html var handler = job.Schedule(_transformAccessArray); // 何かしらの処理をメインスレッドでしても良い //Thread.Sleep(10); handler.Complete(); } }
TransformAccessArray
を使うぐらいで、基本的にIJobParallelFor
の際と変わりません。
またProfiler
で確認すると確かにマルチスレッドで動作しているようです。

比較
Editor上で、10秒間0.2秒毎に算出した平均FPSの結果が以下になります。
Main Threadのみ | IJobParallelForTransform | IJobParallelForTransform + Burst |
---|---|---|
31.75824 | 34.74327 | 35.0083 |
思ったより微妙な差になりましたが、Main Threadのみ < IJobParallelForTransform < IJobParallelForTransform + Burst
という結果になりました。
コードは以下の通り。
メインスレッドのみ
private void Update() { for (var i = 0; i < _transformAccessArray.length; i++) { var distance = Vector3.Distance(_transformAccessArray[i].position, Vector3.zero); _transformAccessArray[i].localPosition += Vector3.up * math.sin(Time.time * 3f + distance * 0.2f); } }
Burst Compiler
[BurstCompile] private struct MyParallelForTransformJob : IJobParallelForTransform { [ReadOnly] public float time; public void Execute(int index, TransformAccess transform) { var distance = Vector3.Distance(transform.position, Vector3.zero); transform.localPosition += Vector3.up * math.sin(time * 3f + distance * 0.2f); } }

さいごに
Youtubeにめちゃくちゃ分かりやすい動画があったので共有しておきます。
www.youtube.com