表示一个作业的接口,该作业独立地对本机容器中的每个元素执行相同的操作,或执行固定次数的迭代操作。
此作业类型的任务计划选项如下
Execute(int index)
对从 0 到提供的长度的每个索引执行一次。
Run
和 Schedule
保证按照顺序调用该作业的 Execute(int index)
方法。 ScheduleParallel
不按顺序调用作业的 Execute
方法,因为它从多个工作线程中被并行调用。
每个迭代必须独立于其他迭代,而且安全系统会强制执行此规则。这些索引没有保证的顺序,并且将在多个内核上并行地执行。
Unity 会自动将任务分割为不少于所提供的 batchSize
的块,并根据工作线程的数量、数组长度和批处理大小安排适当数量的任务。您应该根据任务中执行的工作量来选择批处理大小。例如,一个简单的任务,例如将几个 Vector3 相加,批处理大小应为 32 到 128。但是,如果执行的工作非常繁重,那么最佳做法是使用较小的批处理大小,例如批处理大小为 1。IJobFor 使用原子操作执行任务窃取。批处理大小可以很小,但它们不是免费的。
您可以使用返回的 JobHandle
来检查任务是否已完成,或将其作为依赖项传递到其他任务。当您将 JobHandle
作为依赖项传递时,它可确保任务在工作线程上一个接一个地执行。
其他资源: IJobForExtensions
using UnityEngine; using Unity.Collections; using Unity.Jobs;
class ApplyVelocityParallelForSample : MonoBehaviour { struct VelocityJob : IJobFor { // Jobs declare all data that will be accessed in the job // By declaring it as read only, multiple jobs are allowed to access the data in parallel [ReadOnly] public NativeArray<Vector3> velocity;
// By default containers are assumed to be read & write public NativeArray<Vector3> position;
// Delta time must be copied to the job since jobs generally don't have concept of a frame. // The main thread waits for the job same frame or next frame, but the job should do work deterministically // independent on when the job happens to run on the worker threads. public float deltaTime;
// The code actually running on the job public void Execute(int i) { // Move the positions based on delta time and velocity position[i] = position[i] + velocity[i] * deltaTime; } }
public void Update() { var position = new NativeArray<Vector3>(500, Allocator.Persistent);
var velocity = new NativeArray<Vector3>(500, Allocator.Persistent); for (var i = 0; i < velocity.Length; i++) velocity[i] = new Vector3(0, 10, 0);
// Initialize the job data var job = new VelocityJob() { deltaTime = Time.deltaTime, position = position, velocity = velocity };
// Schedule job to run immediately on main thread. First parameter is how many for-each iterations to perform. job.Run(position.Length);
// Schedule job to run at a later point on a single worker thread. // First parameter is how many for-each iterations to perform. // The second parameter is a JobHandle to use for this job's dependencies. // Dependencies are used to ensure that a job executes on worker threads after the dependency has completed execution. // In this case we don't need our job to depend on anything so we can use a default one. JobHandle scheduleJobDependency = new JobHandle(); JobHandle scheduleJobHandle = job.Schedule(position.Length, scheduleJobDependency);
// Schedule job to run on parallel worker threads. // First parameter is how many for-each iterations to perform. // The second parameter is the batch size, // essentially the no-overhead innerloop that just invokes Execute(i) in a loop. // When there is a lot of work in each iteration then a value of 1 can be sensible. // When there is very little work values of 32 or 64 can make sense. // The third parameter is a JobHandle to use for this job's dependencies. // Dependencies are used to ensure that a job executes on worker threads after the dependency has completed execution. JobHandle scheduleParallelJobHandle = job.ScheduleParallel(position.Length, 64, scheduleJobHandle);
// Ensure the job has completed. // It is not recommended to Complete a job immediately, // since that reduces the chance of having other jobs run in parallel with this one. // You optimally want to schedule a job early in a frame and then wait for it later in the frame. scheduleParallelJobHandle.Complete();
Debug.Log(job.position[0]);
// Native arrays must be disposed manually. position.Dispose(); velocity.Dispose(); } }
Execute | 针对特定迭代索引执行任务。 |