ジョブをスケジュールする場合、1 つのタスクをこなすジョブ 1 つだけが可能です。しかし、同じ処理を多くのオブジェクトに対して行う必要がある場合もあります。これを行うには、IJobParallelFor を継承する ParallelFor ジョブタイプを使用します。
ParallelFor ジョブは、データソースとして動作するデータの NativeArray を使用し、複数の CPU コアで実行されます。コアごとに 1 つのジョブがあり、それぞれがワークロードのサブセットを処理します。
IJobParallelFor は IJob のように動作しますが、1 つの Execute メソッドではなく、データソースの項目ごとに Execute メソッドが 1 回実行されます。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 つのジョブをスケジュールし、そのネイティブジョブをバッチ処理に渡して処理します。
任意のネイティブジョブが他のジョブより早くバッチを完了すると、他のネイティブジョブから残っているバッチをもらい受けて処理します。キャッシュの局所性を確保するために、1 度にネイティブジョブの残りのバッチの半分しか受け取りません。
プロセスを最適化するには、バッチ数を指定する必要があります。バッチ数は、取得するジョブの数、スレッド間の作業の再配布の仕方を制御します。バッチ数が 1 であるなど、バッチ数が少ないと、スレッド間でより均等に作業を分散できます。オーバーヘッドがあるので、バッチ数を増やす方がよい場合もあります。1 から始めて、パフォーマンスの向上がごくわずかになるまでバッチ数を増やすことが有効な方法です。
以下は、ParallelFor ジョブのスケジューリングの例です。
ジョブコード
// Job adding two floating point values together
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;
// Schedule the job with one Execute per index in the results array and only 1 item per processing batch
JobHandle handle = jobData.Schedule(result.Length, 1);
// Wait for the job to complete
handle.Complete();
// Free the memory allocated by the arrays
a.Dispose();
b.Dispose();
result.Dispose();
ParallelForTransform ジョブは、Transform で動作するように特別に設計された、もう 1 つのタイプの ParallelFor ジョブです。ジョブから Transform 操作を効率的に行う場合に便利です。