今回はNativeList
をIJobParallelFor
を使用して利用してみます。
NativeListをIJobParallelForで使う
NativeListは要素を増減出来るという点で言えば便利な機能です。ただしIJob
を使用している場合には大体の機能を使えるのですがIJobParallelFor
で書込を行おうとすると、InvalidOperationException: The previously scheduled job Job名 reads from the NativeArray NativeList名. You must call JobHandle.Complete() のようなエラーが表示されて実行できません。
これを回避するには、NativeList.AsDeferredJobArray()
を使用して、NativeListをNativeArrayとして扱います。これはコピーではないので、NativeArrayの変更はNativeListにも反映されます。
なお[ReadOnly]
を使用している場合には、こんな事をせずともListのまま使用できます。また、NativeArray
に変換しているためAddは出来ません。
また、Job
のパッケージが必要です。
使い方(NativeListの用意)
まずNativeListの用意をします。NativeListのAddは並列処理出来ないので、そこは諦めます。
ジョブ側
struct AddJob : IJob { public NativeQueue<int> queue; public NativeList<int> list; public void Execute() { while (queue.TryDequeue(out int item)) { if (item % 2 == 0) // 2で割り切れる要素だけ追加 list.Add(item); } } }
呼び出す側
// Listに登録する要素を NativeQueue<int> queue = new NativeQueue<int>(Allocator.TempJob); queue.Enqueue(3); queue.Enqueue(2); queue.Enqueue(4); queue.Enqueue(5); NativeList<int> list = new NativeList<int>(8, Allocator.TempJob); // 内容の更新 var handle = new AddJob { queue = queue, list = list }.Schedule();
使い方(NativeListの内容を更新)
次にNativeList
をIJobParallelFor
で更新します。更新する際には上に書いたとおりAsDeferredJobArray
を使用します。特に指定せずとも自動で変換されるっぽいですが、精神の安全のために使用しておきます。
まずジョブですが、普通にNativeArrayを使用します。ここにNativeListの要素が格納されます。
struct UpdateJob : IJobParallelFor { public NativeArray<int> array; public void Execute(int index) { array[index] += 1; } }
使用する側は少しだけ特殊です。まずNativeListをNativeArrayに変換しているのが一点、そしてジョブの長さにNativeListを設定する点です。
後者は普通にNativeListの長さがジョブ発行時にはわからないので、そういった場合の対策といった感じでしょうか。
handle = new UpdateJob { array = list.AsDeferredJobArray() // AsDeferredJobArrayでNativeArrayにする }.Schedule(list, 4, handle); // 要素数の部分にはlistを登録
これでListの中身を並列処理で書き換えました。
中身を確認する
最後に中身を確認します。こちらは普通に[Readonly]な NativeListで問題ありません。
struct ShowLogJob : IJobParallelFor { [ReadOnly] public NativeList<int> list; public void Execute(int index) { Debug.Log(list[index]); } }
使う側も概ね同じです。
handle = new ShowLogJob { list = list }.Schedule(list, 8, handle);
実行結果
処理の内容はコードは、
- 3/2/4/5をQueueに追加
- 2で割り切れる数(2/4)をListに追加
- Listの要素に1を追加(2/4 が 3/5になる)
- Listの中身をDebugLogで表示
という内容で、実際確認してみると、ちゃんと期待通りの数字が出ています。
コード全文(を少し改造したもの)
感想
NativeListで並列処理出来ないかと色々と確認した結果、最終的にコレになりました。Addが出来ないのは残念ですが、まぁ。