Version: 2018.4
JobHandle 和依赖项
ParallelForTransform 作业

ParallelFor 作业

调度作业时,只能有一个作业正在执行一项任务。在游戏中,通常希望对大量对象执行相同的操作。有一个称为 IJobParallelFor 的单独作业类型可以处理此问题。

注意:“ParallelFor”作业是 Unity 中对于任何实现 IJobParallelFor 接口的结构的统称。

ParallelFor 作业使用一个数据 NativeArray 作为其数据源。ParallelFor 作业在多个核心上运行。每个核心有一个作业,每个作业处理一部分工作量。IJobParallelFor 的行为类似于 IJob,但其并非调用单个 Execute 方法,而是对数据源中的每一项都调用一次 Execute 方法。Execute 方法中有一个整数参数。该索引用于访问和操作作业实现中的数据源的单个元素。

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,Unity C# 作业系统无法知道您希望将哪个用作数据源。长度还告诉 C# 作业系统应该有多少个 Execute 方法。

在后台,ParallelFor 作业的调度更加复杂。在调度 ParallelFor 作业时,C# 作业系统将工作分成多个批次以便在多个核心之间分配任务。每个批次包含一小部分 Execute 方法。然后,针对每个 CPU 核心,C# 作业系统会在 Unity 本机作业系统中调度最多一个作业,并向该本机作业传递一些需要完成的批次。

一个 ParallelFor 作业在多个核心之间划分批次
一个 ParallelFor 作业在多个核心之间划分批次

一个本机作业在其他作业之前完成自己负责的批次时,它会从其他本机作业窃取剩余批次。它一次只能窃取本机作业剩余批次的一半,以确保缓存局部性

要优化该过程,必须指定批次计数。批次计数可以控制您获得的作业数量,以及线程之间重新分配工作的细化程度。批次计数较低(例如 1)可以使线程之间的工作分布更均匀。这样确实会带来一些开销,所以有时候增加批次计数会更好。一种有效的策略是从 1 开始并增加批次计数直到性能增益可忽略不计。

调度 ParallelFor 作业的示例

作业代码

// 将两个浮点值相加的作业
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;

// 调度作业,为结果数组中的每个索引执行一个 Execute 方法,且每个处理批次只处理一项
JobHandle handle = jobData.Schedule(result.Length, 1);

// 等待作业完成
handle.Complete();

// 释放数组分配的内存
a.Dispose();
b.Dispose();
result.Dispose();

  • 2018–06–15 页面已发布并进行了编辑审查

  • 2018.1 版中公开了 C# 作业系统 NewIn20181

JobHandle 和依赖项
ParallelForTransform 作业