天天看點

8天玩轉并行開發——第七天 簡要分析任務與線程池

         其實說到上一篇,我們要說的task的知識也說的差不多了,這一篇我們開始站在理論上了解下“線程池”和“任務”之間的關系,不管是

說線程還是任務,我們都不可避免的要讨論下線程池,然而在.net 4.0以後,線程池引擎考慮了未來的擴充性,已經充分利用多核微處理器

架構,隻要在可能的情況下,我們應該盡量使用task,而不是線程池。

首先看一下task的結構

8天玩轉并行開發——第七天 簡要分析任務與線程池

從圖中我們可以看出task.factory.startnew()貌似等同于用threadpool.queueuserworkitem()建立,但是請注意,我是用tpl的形式

使用線程池,要知道task出現以後,一直标榜着以更少的工作量,更低的性能消耗來pk原始線程。

     這裡簡要的分析下clr線程池,其實線程池中有一個叫做“全局隊列”的概念,每一次我們使用queueuserworkitem的使用都會産生一個

“工作項”,然後“工作項”進入“全局隊列”進行排隊,最後線程池中的的工作線程以fifo的形式取出,效果圖類似如下:

8天玩轉并行開發——第七天 簡要分析任務與線程池

這裡要值得一提的是,在.net 4.0之後“全局隊列”采用了無鎖算法,相比以前版本鎖定“全局隊列”帶來的性能瓶頸有了很大的改觀。那麼任務

委托的線程池不光有“全局隊列”,而且每一個工作線程都有”局部隊列“,效果圖如下

8天玩轉并行開發——第七天 簡要分析任務與線程池

我們的第一反應肯定就是“局部隊列“有什麼好處,可以考慮這樣的情況,當我們new一個task的時候“工作項”就會進去”全局隊列”,如果我們的

task執行的非常快,那麼“全局隊列“就會fifo的非常頻繁,那麼有什麼辦法緩解呢?當我們的task在嵌套的場景下,“局部隊列”就要産生效果了,

比如我們一個task裡面有3個task,那麼這3個task就會存在于“局部隊列”中。

8天玩轉并行開發——第七天 簡要分析任務與線程池

從圖中可以看到,其實“局部隊列“起到了一個分流的作用,也叫做”任務内聯化“,”局部隊列“采用的是”lifo"的形式,其實這樣的形式也是

為了提升性能之用,因為run3送到“局部隊列”中時可能還存在cpu的高速緩存中,是以從“局部隊列”中取出來相對來說更快一點,最後的效

果就是run3要理論上優先于run2,run1先執行。

     現在我們再來考慮這樣一種情況,比如有兩個人,一個人幹完了配置設定給自己的所有活,而另一個人卻還有很多的活,從人情上說,閑的人應

該接手點忙的人的活,同樣,對應圖中“線程2“跑完了“局部隊列”中的所有任務,并且同時發現”全局隊列“中已經沒有可以跑的”任務“了,然而

“線程1”裡面還有run1,run2,run3,那麼此時“線程2”采用“fifo”的形式竊取“線程1”裡面的任務。

8天玩轉并行開發——第七天 簡要分析任務與線程池

    從上面種種情況我們看到,這些分流和負載都是普通threadpool.queueuserworkitem所不能辦到的,是以說在.net 4.0之後,我們

盡可能的使用tpl,抛棄threadpool。