ジョブをスケジュール する場合、1 つのタスクをこなすジョブは 1 つだけです。しかし、同じ処理を多くのオブジェクトに対して行う必要がある場合もあるでしょう。これを行うには、IJobParallelFor
](Scriptref:Unity.Jobs.IJobParallelFor) を継承する ParallelFor ジョブタイプを使います。
arallelFor ジョブはデータの NativeArray
をデータソースとして使用します。ParallelFor ジョブは複数の CPU コアで実行されます。コアごとに 1 つのジョブがあり、それぞれがワークロードのサブセットを処理します。
IJobParallelFor
は IJob
のように動作しますが、Execute
メソッドを 1 回呼び出すのではなく、Execute
メソッドをデータソースのアイテムごとに 1 回呼び出します。データソースのアイテムごとに一度Execute
メソッドを呼び出します。Execute
メソッドには整数のパラメーターがあります。このインデックスはジョブの実装の際に、データソースの 1 つの要素にアクセスして操作するためのものです。
以下は ParallelFor ジョブ定義の例です。
struct IncrementByDeltaTimeJob: IJobParallelFor
{
public NativeArray<float> values;
public float deltaTime;
public void Execute (int index)
{
float temp = values[index];
temp += deltaTime;
values[index] = temp;
}
}
ParallelFor
のジョブをスケジュールするために、分割する NativeArray
データソースの長さを指定する必要があります。構造体にいくつかのデータソースが存在する場合、ジョブシステムは、どの NativeArray
をデータソースとして使用したいかを知ることができません。長さによっても、ジョブシステムにいくつの Execute
メソッドがあるかを予測することができます。
Unity のネイティブコードでは、ParallelFor
ジョブのスケジューリングはより複雑です。ParallelFor
ジョブをスケジュールするとき、ジョブシステムは作業をバッチに分割してコア間に分散します。各バッチに Execute
メソッドのサブセットが含まれています。ジョブシステムは、CPU コアごとに Unity のネイティブジョブシステムで 1 つのジョブをスケジュールし、そのネイティブジョブをバッチ処理に渡して処理します。
任意のネイティブジョブが他のジョブより早くバッチを完了すると、他のネイティブジョブから残っているバッチを Work stealing 処理 (もらい受けて処理) します。キャッシュの局所性 を確保するために、1 度にネイティブジョブの残りのバッチの半分しか受け取りません。
プロセスを最適化するには、バッチ数を指定する必要があります。バッチ数は、取得するジョブの数、スレッド間の作業の再配布の仕方を制御します。バッチ数が 1 であるなど、バッチ数が少ないと、スレッド間でより均等に作業を分散できます。オーバーヘッドがあるので、バッチ数を増やす方がよい場合もあります。 1 から始まり、パフォーマンスの向上がごくわずかになるまでバッチ数を増やすことが有効な方法です。
以下は、ParallelFor ジョブのスケジューリングの例です。
ジョブコード
// 2 つの浮動小数点の値を加算するジョブ
public struct MyParallelJob : IJobParallelFor
{
[ReadOnly]
public NativeArray<float> a;
[ReadOnly]
public NativeArray<float> b;
public NativeArray<float> result;
public void Execute(int i)
{
result[i] = a[i] + b[i];
}
}
メインスレッドコード
NativeArray<float> a = new NativeArray<float>(2, Allocator.TempJob);
NativeArray<float> b = new NativeArray<float>(2, Allocator.TempJob);
NativeArray<float> result = new NativeArray<float>(2, Allocator.TempJob);
a[0] = 1.1;
b[0] = 2.2;
a[1] = 3.3;
b[1] = 4.4;
MyParallelJob jobData = new MyParallelJob();
jobData.a = a;
jobData.b = b;
jobData.result = result;
// 結果の配列の各インデックスに 1 つずつの実行と、各バッチ処理に 1 要素をもつジョブをスケジュールします
JobHandle handle = jobData.Schedule(result.Length, 1);
// ジョブが完了するのを待機します
handle.Complete();
// 配列に割り当てられたメモリを開放します
a.Dispose();
b.Dispose();
result.Dispose();
ParallelForTransform
ジョブは、Transforms を操作するために特別に設計されたParallelFor
ジョブの別のタイプです。ジョブから Transform 操作を効率的に行うのに便利です。詳細については、ParallelForTransform API ドキュメントを参照してください。