日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Unity C# Job System介绍(四) 并行化Job和故障排除(完结)

發布時間:2023/12/13 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unity C# Job System介绍(四) 并行化Job和故障排除(完结) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

并行化job

ParallelFor jobs?docs.unity3d.com

當調度Jobs時,只能有一個job來進行一項任務。在游戲中,非常常見的情況是在一個龐大數量的對象上執行一個相同的操作。這里有一個獨立的job類型叫做IJobParallelFor來處理此類問題。ParallelFor jobs當調度Jobs時,只能有一個job來進行一項任務。在游戲中,非常常見的情況是在一個龐大數量的對象上執行一個相同的操作。這里有一個獨立的job類型叫做IJobParallelFor來處理此類問題。

注意:“并行化”job是Unity中所有實現了IJobParallelFor接口的結構的總稱。

一個并行化job使用一個NativeArray存放數據來作為它的數據源。并行化job橫跨多個核心執行。每個核心上有一個job,每個job處理一部分工作量。IJobParallelFor的行為很類似于IJob,但是不同于只執行一個Execute方法,它會在數據源的每一項上執行Execute方法。Execute方法中有一個整數型的參數。這個索引是為了在job的具體操作實現中訪問和操作數據源上的單個元素。

一個定義并行化Job的例子:

struct IncrementByDeltaTimeJob: IJobParallelFor {public NativeArray<float> values;public float deltaTime;public void Execute (int index){float temp = values[index];temp += deltaTime;values[index] = temp;} }

調度并行化job

當調度并行化job時,你必須指定你分割NativeArray數據源的長度。在結構中同時存在多個NativeArrayUnity時,C# Job System不知道你要使用哪一個NativeArray作為數據源。這個長度同時會告知C# Job System有多少個Execute方法會被執行。

在這個場景中,并行化job的調度會更復雜。當調度并行化任務時,C# Job System會將工作分成多個批次,分發給不同的核心來處理。每一個批次都包含一部分的Execute方法。隨后C# Job System會在每個CPU核心的Unity原生Job System上調度最多一個job,并傳遞給這個job一些批次的工作來完成。

一個并行化job劃分批次到多個CPU核心

當一個原生job提前完成了分配給它的工作批次后,它會從其他原生job那里獲取其剩余的工作批次。它每次只獲取那個原生job剩余批次的一半,為了確保緩存局部性(cache locality)。

為了優化這個過程,你需要指定一個每批次數量(batch count)。這個每批次數量控制了你會生成多少job和線程中進行任務分發的粒度。使用一個較低的每批次數量,比如1,會使你在線程之間的工作分配更平均。它會帶來一些額外的開銷,所以有時增加每批次數量會是更好的選擇。從每批次數量為1開始,然后慢慢增加這個數量直到性能不再提升是一個合理的策略。

調度并行化job的例子:

job代碼

// Job adding two floating point values together 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;// Schedule the job with one Execute per index in the results array and only 1 item per processing batch JobHandle handle = jobData.Schedule(result.Length, 1);// Wait for the job to complete handle.Complete();// Free the memory allocated by the arrays a.Dispose(); b.Dispose(); result.Dispose();

ParallelForTransform jobs

https://docs.unity3d.com/Manual/JobSystemParallelForTransformJobs.html

一個ParallelForTransform?job是另一個類型的ParallelFor?job;它是專門為了Transforms上的操作設計的。

注意:ParallelForTransform job是Unity中所有實現了IJobParallelForTransform接口的結構的總稱。

C# Job System建議和故障排除

C# Job System tips and troubleshooting?docs.unity3d.com

當你使用Unity C# Job System時,確保你遵守以下幾點:C# Job System tips and troubleshooting當你使用Unity C# Job System時,確保你遵守以下幾點:

不要從一個job中訪問靜態的數據

在所有的安全性系統中你都應當避免從一個job中訪問靜態數據。如果你訪問了錯誤的數據,你可能會使Unity崩潰,通常是以意想不到的方式。舉例來說,訪問一個MonoBehaviour可以導致域重新加載時崩潰。

注意:因為這個風險,未來版本的Unity會通過靜態分析來阻止全局變量在job中的訪問。如果你確實在job中訪問了靜態數據,你應當預見到你的代碼會在Unity未來的版本中報錯。

刷新已調度的批次

當你希望你的job開始執行時,你可以通過JobHandle.ScheduleBatchedJobs來刷新已調度的批次。注意調用這個接口時會對性能產生負面的影響。不刷新批次將會延遲調度job,直到主線程開始等待job的結果。在任何其他情況中,你應當調用JobHandle.Complete來開始執行過程。

注意:在Entity Component System(ECS)中批次會暗中為你進行刷新,所以調用JobHandle.ScheduleBatchedJobs是不必要的。

不要試圖去更新NativeContainer的內容

由于缺乏引用返回值,不可能去直接修改一個NativeContainer的內容。例如,nativeArray[0]++ ;和 var temp = nativeArray[0]; temp++;一樣,都沒有更新nativeArray中的值。

你必須從一個index將數據拷貝到一個局部臨時副本,修改這個副本,并將它保存回去,像這樣:

MyStruct temp = myNativeArray[i]; temp.memberVariable = 0; myNativeArray[i] = temp;

調用JobHandle.Complete來重新獲得歸屬權

在主線程重新使用數據前,追蹤數據的所有權需要依賴項都完成。只檢查JobHandle.IsCompleted是不夠的。你必須調用JobHandle.Complete來在主線程中重新獲取NaitveContainer類型的所有權。調用Complete同時會清理安全性系統中的狀態。不這樣做的話會造成內存泄漏。這個過程也在你每一幀都調度依賴于上一幀job的新job時被采用。

在主線程中調用Schedule和Complete

你只能在主線程中調用ScheduleComplete方法。如果一個job需要依賴于另一個,使用JobHandle來處理依賴關系而不是嘗試在job中調度新的job。

在正確的時間調用Schedule和Complete

一旦你擁有了一個job所需的數據,盡可能快地在job上調用Schedule,在你需要它的執行結果之前不要調用Complete。一個良好的實踐是調度一個你不需要等待的job,同時它不會與當前正在運行的其他job產生競爭。舉例來說,如果你在一幀結束和下一幀開始之前擁有一段沒有其他job在運行的時間,并且可以接受一幀的延遲,你可以在一幀結束的時候調度一個job,在下一幀中使用它的結果。或者,如果這個轉換時間已經被其他job占滿了,但是在一幀中有一大段未充分利用的時段,在這里調度你的job會更有效率。

將NativeContainer標記為只讀的

記住job在默認情況下擁有NativeContainer的讀寫權限。在合適的NativeContainer上使用[ReadOnly]屬性可以提升性能。

檢查數據的依賴

在Unity的Profiler窗口中,主線程中的"WaitForJobGroup"標簽表明了Unity在等待一個工人線程上的job結束。這個標簽可能意味著你以某種方式引入了一個資源依賴,你需要去解決它。查找JobHandle.Complete來追蹤你在什么地方有資源依賴,導致主線程必須等待。

調試job

job擁有一個Run方法,你可以用它來替代Schedule從而讓主線程立刻執行這個job。你可以使用它來達到調試目的。

不要在job中開辟托管內存

在job中開辟托管內存會難以置信得慢,并且這個job不能利用Unity的Burst編譯器來提升性能。Burst是一個新的基于LLVM的后端編譯器技術,它會使事情對于你更加簡單。它獲取C# job并利用你平臺的特定功能產生高度優化的機器碼。

更多信息

  • 觀看Unity GDC 2018: C# Job System的片段列表
  • 獲取C# Job Syetem與ECS交互的更進一步信息,查看ECS package documentation on GitHub

總結

以上是生活随笔為你收集整理的Unity C# Job System介绍(四) 并行化Job和故障排除(完结)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。