UE4中已經有了基於FQueuedThreadPool的AsyncTask,為什麼還要加入TaskGraph,UE4的TaskGraph系統與U3D的JobSystem比有什麼區別。(理解的比較片面,歡迎大神糾正)

(一)首先,參考官方文檔和閱讀一手資料是求真比較好的途徑。

1、 多線程和並發編程請參考圖書《Game Engine Architecture》第四章節Parallelism and Concurrent Programming。

2、 UE4的多線程和並發編程請參考Gerke Max Preussner的PPT文檔Concurrency & Parallelism in UE4和YouTube的視頻。

(二)TaskGraph結構

1、基於有向無環圖的Task集合

wiki圖片

Task Node與Task Node的聯繫

每一個Node(Task)都有一個數據結構SubsequentList保存對它有依賴的其他Node(task),如果一個Node Task依賴計數為0而且沒有被lock,則這個Task可以加入到Queue,等待執行。

2、管理TaskNode節點和線程的Manager:TaskGraphImplementationSingleton

負責將颳起的Thread喚醒,同時將準備好的task node插入到對應的buffer中(namethread和worker thread不同)

3、線程組

FTaskThreadBase繼承出來兩個類FNamedTaskThread、FTaskThreadAnyThread

命名線程有自己的存放task node的隊列,而工作線程需要在空閑時從TaskGraphImplementation中FindWork()。

(三) TaskGraph使用方法

這是簡單的用法,TaskGraph在利用NameThread的空閑時間和使用Fence的用例目前還沒看全,後面補上:)

(四) 問題

1、TaskGraph如何處理Race Condition?

TaskGraph的實現基本上是LockFree的,處理並發的成本比FQueuedThreadPool中使用Lock的方式應該要低很多。

以下是幾個比較重要的Lockfree的數據結構:

A、 保存節點之間依賴關係的 SubsequentList

/** Threadsafe list of subsequents for the event **/
TClosableLockFreePointerListUnorderedSingleConsumer<FBaseGraphTask,0> SubsequentList;

B、 存放Task的FStallingTaskQueue中的

FLockFreePointerFIFOBase<T,TPaddingForCacheContention> PriorityQueues[NumPriorities];

2、TaskGraph和QueuedThreadPool區別

QueuedThreadPool還是基於鎖的,理論是比TaskGraph慢,但是QueuedThreadPool和AsyncTask的結構比較簡單,容易應用。而且使用AsyncTask不容易影響遊戲幀數,因為在TaskGraph中發布的任務可能在遊戲主線程或者渲染線程中運行,如果任務的執行時間比較長,可能阻塞住以上兩個命名線程。

3、UE4中TaskGraph和Unity中JobSystem的比較

Unity中的JobSystem沒有深入瞭解,從表象上看,UE4中TaskGraph和Unity中JobSystem負責的任務應該是一樣的,而Unity的ECS結構,對Job進行了細緻的切分,對象設計的思路應該更新些,與JobSystem的結構更緊密。而UE4的Object系統,要使用TaskGraph,相對困難些。但從Profile的結果來看,UE4 的TaskGraph對CPU核心的利用率會比Unity高些。

以上只是個人簡單的分析,必有差漏,歡迎拍磚~~


推薦閱讀:
相關文章