Unity C# Job System介紹(三) Job的創建和調度

創建Jobs

Unity - Manual: Creating jobs​docs.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 jobs​docs.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();

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章