渋谷ほととぎす通信

完全趣味でやってるUnityメモ。説明できないところを説明できるようにするための個人ブログ。昨日の自分より少しでも大きくなれるように。。。 ※所属団体とは一切関係がありません

IJobParallelForで並列処理させるジョブを作ってみる


f:id:esakun:20150730215258g:plain
前回はIJobインターフェースでJobSystemを使ってみました。

IJobインターフェースで作ったジョブは1つのWorkerThreadに処理を分散することしかできませんでしたが、今回はもっと多くのWorkerThreadに処理を分散させてみようと思います。

IJobParallelForインターフェースを使ってジョブを作る

Unity - Scripting API: IJobParallelFor

IJobParallelForインターフェースを使うと、複数のスレッドに分散させて配列要素を並列で実行することができます。また、この配列はNativeContainerである必要があります。

struct VelocityJob : IJobParallelFor
{
    // 処理するバッファはNativeContainerである必要がある
    [ReadOnly]
    public NativeArray<Vector3> velocity;
    public NativeArray<Vector3> position;
    public float deltaTime;
    /// <summary>
    /// ジョブの処理内容
    /// </summary>
    public void Execute(int index)
    {
        position[index] = position[index] + velocity[index] * deltaTime;
    }
}

上記のようにジョブを作ります。
Execute内で処理できる要素番号が引数で渡ってきますが、それ以外の要素数を操作することはできません。 position[index + 1]とかにアクセスするとエラーが出ます。

f:id:esakun:20180910233824p:plain:w450
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~C# Jo…P29より
分散処理は上のようなイメージらしいです。

ジョブの実行

var job = new VelocityJob() {
    deltaTime = Time.deltaTime,
    position = position,
    velocity = velocity
};
// ジョブを実行
// 第2引数に0を入れるといい感じにスレッドに振り分けてくれるらしい
JobHandle jobHandle = job.Schedule(_count, 0);
// ジョブ完了の待機
jobHandle.Complete();

Scheduleメソッドの第2引数にはバッチ数を指定します。0を指定するといい感じに分散してくれるらしいです。

パフォーマンスについて

ジョブ未使用状態
f:id:esakun:20180910023539p:plain:w500

  • MainThreadのUpdate処理時間 : 28.4ms

ジョブ使用状態(No Burst)
f:id:esakun:20180910023656p:plain:w500

  • MainThreadのUpdate処理時間 : 16.06ms
  • ジョブ実行時間 : 6.5ms

ジョブ使用状態(Burst)

f:id:esakun:20180910024216p:plain:w500

そしてBurstCompilerを使うと、

  • MainThreadのUpdate処理時間 : 10.15ms
  • ジョブ実行時間 : 0.75ms

前回記事のIJobインターフェースで作った処理をIJobParallelForに置き換えただけですが、複数のWorkerThreadを使用している分IJobよりパフォーマンスが出ているようです。

  • IJob・・・1つの処理をWorkerThreadに分散したい場合
  • IJobParallelFor・・・・多くの要素を並列処理したい場合

という使い分けをするのだろうと思いました。

環境

  • Unity2018.2.5.f1

今回のソースコードはこちら

パフォーマンス検証のためジョブ使用/未使用をuseJobフラグで分けてます。