Version: 2019.1
JobHandle と依存関係
ParallelForTransform ジョブ

ParallelFor ジョブ

ジョブのスケジューリング の場合は、1 つのジョブは 1 つのタスクしか実行できません。ゲームでは、同じ操作を多くのオブジェクトに行ないたいのが一般的です。これを処理するために、IJobParallelFor という別のジョブタイプがあります。

注意 ParallelFor ジョブは、 IJobParallelFor インターフェースを実装する構造体を指す Unity 内での総称です。

ParallelFor ジョブはデータの NativeArray をデータソースとして使用します。ParallelFor ジョブは複数のコアで実行できます。コアごとに 1 つのジョブがあり、それぞれのジョブがワークロードのサブセットを処理します。IJobParallelForIJob のように動作しますが、Execute メソッドを 1 回呼び出すのではなく、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 ジョブのスケジュール

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

見えないところでは、ParallelFor ジョブのスケジューリングはより複雑です。ParallelFor ジョブをスケジュールするとき、C# Job System は作業をバッチに分割してコア間に分散します。各バッチに Execute メソッドのサブセットが含まれています。C# Job System は、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();

  • 2018–06–15 編集レビュー を行ってパブリッシュされたページ

  • C# Job System は 2018.1 で公開NewIn20181

JobHandle と依存関係
ParallelForTransform ジョブ