創建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();