Version: 2022.3
言語: 日本語
ジョブの依存関係
マルチプレイヤーとネットワーク

ParallelFor ジョブ

ジョブをスケジュール する場合、1 つのタスクをこなすジョブは 1 つだけです。しかし、同じ処理を多くのオブジェクトに対して行う必要がある場合もあるでしょう。これを行うには、IJobParallelFor](Scriptref:Unity.Jobs.IJobParallelFor) を継承する ParallelFor ジョブタイプを使います。

arallelFor ジョブはデータの NativeArray をデータソースとして使用します。ParallelFor ジョブは複数の CPU コアで実行されます。コアごとに 1 つのジョブがあり、それぞれがワークロードのサブセットを処理します。

IJobParallelForIJob のように動作しますが、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 ジョブのスケジュール

ParallelFor のジョブをスケジュールするために、分割する NativeArray データソースの長さを指定する必要があります。構造体にいくつかのデータソースが存在する場合、ジョブシステムは、どの NativeArray をデータソースとして使用したいかを知ることができません。長さによっても、ジョブシステムにいくつの Execute メソッドがあるかを予測することができます。

Unity のネイティブコードでは、ParallelFor ジョブのスケジューリングはより複雑です。ParallelFor ジョブをスケジュールするとき、ジョブシステムは作業をバッチに分割してコア間に分散します。各バッチに Execute メソッドのサブセットが含まれています。ジョブシステムは、CPU コアごとに Unity のネイティブジョブシステムで 1 つのジョブをスケジュールし、そのネイティブジョブをバッチ処理に渡して処理します。

コアをまたいでバッチを分割する ParallelFor ジョブ
コアをまたいでバッチを分割する ParallelFor ジョブ

任意のネイティブジョブが他のジョブより早くバッチを完了すると、他のネイティブジョブから残っているバッチを 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 ジョブ

ParallelForTransform ジョブは、Transforms を操作するために特別に設計されたParallelFor ジョブの別のタイプです。ジョブから Transform 操作を効率的に行うのに便利です。詳細については、ParallelForTransform API ドキュメントを参照してください。

ジョブの依存関係
マルチプレイヤーとネットワーク