溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Task的運行原理和工作竊取(work stealing)

發(fā)布時間:2020-07-22 10:00:22 來源:網(wǎng)絡 閱讀:6702 作者:cnn237111 欄目:編程語言

在net4.0以前,當調(diào)用ThreadPool.QueueUserWorkItem方法往線程池中插入作業(yè)時,會把作業(yè)內(nèi)容(其實就是一個委托)放到線程池中的一個全局隊列中,然后線程池中的線程按照先進先出的方式取出作業(yè),并處理。

如下圖中的方式,主程序創(chuàng)建了Item到Queue中,然后分配到了各個工作線程中。

Task的運行原理和工作竊?。╳ork stealing)    
但是在.net 4.0以后,線程池做了一些改進,比如增加了TPL(Task Parallel Library),TPL使用到了.net 4.0中新增加的一些特性。這些特性只能通過TPL運用,不能直接通過ThreadPool類運用 。TPL中的Task并不是線程,Task的執(zhí)行是需要依靠線程池中的線程來完成的。

創(chuàng)建和啟動一個Task類似調(diào)用ThreadPool.QueueUserWorkItem,但不同的是線程池中的每一個線程都有一個本地隊列。線程池通過一個任務調(diào)度器來分配任務,當主程序創(chuàng)建了一個Task后,由于創(chuàng)建這個Task的線程不是線程池中的線程,則任務調(diào)度器會把該Task放入全局隊列中。

如果這個Task是由線程池中的線程創(chuàng)建,并且未設置TaskCreationOptions.PreferFairness標記(默認情況下未設置),則任務調(diào)度器會把該Task放入到該線程的本地隊列中。如果設置了TaskCreationOptions.PreferFairness標記,則放入全局隊列。

如下面的演示圖,Task1和Task2都是主程序創(chuàng)建的,因此都是放在全局隊列中,當工作者線程處理Task2時,創(chuàng)建了一個Task3,此時Task3被放入本地隊列

Task的運行原理和工作竊?。╳ork stealing)

為什么要設計本地隊列?這樣做的優(yōu)勢是充分利用并行。隨著越來越多線程競爭工作項,所有的線程訪問單一的隊列并不是最優(yōu)的,并且也不安全。所以,將任務放入本地隊列,并且由同一個線程處理,這就避免了競爭。  
本地隊列中的Task,線程會按照LIFO的方式去處理。這是因為在大多數(shù)場景下,最后創(chuàng)建的Task可能仍然在cache中,處理它能夠提供緩存命中率。顯然這意味放棄部分公平性而保證性能。如下面的演示圖,

工作者線程1創(chuàng)建了Task2,Task2創(chuàng)建了Task3,Task4,Task5,但最先處理的還是Task5。


線程竊取work stealing    
當A線程開始執(zhí)行的時候,優(yōu)先總是處理本地隊列中的任務,當它發(fā)現(xiàn)本地隊列已經(jīng)空了,那么它會去全局隊列中獲取Task,當全局隊列中也是空的,那么就會發(fā)生工作竊?。╳ork stealing)。任務調(diào)度器會把該線程池中額外的任務分配給A線程處理,其效果就好比該線程會才從其他線程的隊列中“竊取”一個Task來執(zhí)行。這樣的目的是提高了cpu的使用效率。

Task的運行原理和工作竊?。╳ork stealing)

這種策略是任務調(diào)度器的默認策略,通常是不需要改變的。如果需要改變,需要在創(chuàng)建任務時,設置任務的TaskCreationOptions.PreferFairness。

----------------------

參考資料

http://www.danielmoth.com/Blog/New-And-Improved-CLR-4-Thread-Pool-Engine.aspx

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI