创建Jobs
Unity - Manual: Creating jobsdocs.unity3d.com
为了在Unity中创建一个job你需要实现IJOb接口。IJob允许你调度一个job,和其他jobs并发执行。Unity - Manual: Creating jobs为了在Unity中创建一个job你需要实现IJOb接口。IJob允许你调度一个job,和其他jobs并发执行。
注意:“job”是Unity中所有实现了IJob接口的结构的总称。
为了创建一个job,你需要: 创建一个实现IJob的结构体 添加job需要使用的成员变量(可以是blittable类型或NativeContainer类型) * 在结构体中添加一个叫Execute的方法并将job的具体逻辑实现放在里面
当job执行的时候,Excute方法在单个核心上运行一次
注意:当设计你的job时,记住你是在一份数据的拷贝上进行操作的,除了在使用NativeContainer的情况下。所以,在主线程访问一个job中数据的唯一方法就是将数据写入NativeContainer。
一个简单job定义的例子
// Job adding two floating point values together
public struct MyJob : IJob
{public float a;public float b;public NativeArray<float> result;public void Execute(){result[0] = a + b;}
}
调度Jobs
Unity - Manual: Scheduling jobsdocs.unity3d.com
为了在主线程中调度一个job,你必须: 实例化一个job 填充job中的数据 * 调用Schedule方法
在合适的时间调用Schedule将job放入到job的执行队列中。一旦job被调度,你不能中途打断一个job的执行。
注意:你只能从主线程中调用Schedule
调度一个job的例子
// Create a native array of a single float to store the result. This example waits for the job to complete for illustration purposes
NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob);// Set up the job data
MyJob jobData = new MyJob();
jobData.a = 10;
jobData.b = 10;
jobData.result = result;// Schedule the job
JobHandle handle = jobData.Schedule();// Wait for the job to complete
handle.Complete();// All copies of the NativeArray point to the same memory, you can access the result in "your" copy of the NativeArray
float aPlusB = result[0];// Free the memory allocated by the result array
result.Dispose();
JobHandle和依赖关系
当你调用Schedule方法时会返回一个JobHandle。你可以在代码中使用JobHandle作为其他jobs的依赖关系。如果一个job依赖于另一个job的结果,你可以将第一个job的JobHandle作为参数传递给第二个job的Schedule方法,像这样:
JobHandle firstJobHandle = firstJob.Schedule();
secondJob.Schedule(firstJobHandle);
组合依赖关系
如果一个job有多个依赖项,你可以使用JobHandle.CombineDependencies方法来合并他们。CombineDependencies允许你将他们传递给Schedule方法。
NativeArray<JobHandle> handles = new NativeArray<JobHandle>(numJobs, Allocator.TempJob);// Populate `handles` with `JobHandles` from multiple scheduled jobs...JobHandle jh = JobHandle.CombineDependencies(handles);
在主线程中等待jobs结束
使用JobHandle来让你的代码在主线程等待直到你的job执行完毕。为了做到这样,需要在JobHandle上调用Complete方法。这样的话,你就确定主线程可以安全访问job之前使用的NativeContainer。
注意:jobs不是在你调度他们的时候就立刻开始执行。如果你在主线程中等待job,并且你需要访问job正在使用的NativeContainer,你可以调用JobHandle.Complete方法。这个方法会刷新内存缓存中的jobs并开始执行。调用JobHandele的Complete会将job的NativeContainer类型数据的归属权交还给主线程。你需要在JobHandle上调用Complete来在主线程再次安全地访问这些NativeContainer类型。你也可以调用一个由job依赖产生的JobHandle的Complete方法来将数据的归属权交还给主线程。举例来说,你可以调用jobA的Complete方法,或者你可以调用依赖于jobA的jobB的Complete方法。两种方法都可以让你在调用Complete后在主线程安全访问jobA使用的NativeContainer类型。
否则,如果你不需要对数据的访问,但你需要明确地刷新这个批次的job。为了做到这点,调用静态方法JobHandle.ScheduleBatchedJobs。注意这个调用会对性能产生负面的影响。
一个关于多重job和依赖的例子
job的代码:
// Job adding two floating point values together
public struct MyJob : IJob
{public float a;public float b;public NativeArray<float> result;public void Execute(){result[0] = a + b;}
}// Job adding one to a value
public struct AddOneJob : IJob
{public NativeArray<float> result;public void Execute(){result[0] = result[0] + 1;}
}
主线程代码:
// Create a native array of a single float to store the result in. This example waits for the job to complete
NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob);// Setup the data for job #1
MyJob jobData = new MyJob();
jobData.a = 10;
jobData.b = 10;
jobData.result = result;// Schedule job #1
JobHandle firstHandle = jobData.Schedule();// Setup the data for job #2
AddOneJob incJobData = new AddOneJob();
incJobData.result = result;// Schedule job #2
JobHandle secondHandle = incJobData.Schedule(firstHandle);// Wait for job #2 to complete
secondHandle.Complete();// All copies of the NativeArray point to the same memory, you can access the result in "your" copy of the NativeArray
float aPlusB = result[0];// Free the memory allocated by the result array
result.Dispose();