天天看點

8天玩轉并行開發——第四天 同步機制(上)

     在并行計算中,不可避免的會碰到多個任務共享變量,執行個體,集合。雖然task自帶了兩個方法:task.continuewith()和task.factory

.continuewhenall()來實作任務串行化,但是這些簡單的方法遠遠不能滿足我們實際的開發需要,從.net 4.0開始,類庫給我們提供了很多

的類來幫助我們簡化并行計算中複雜的資料同步問題。

大體上分為二種:

①   并發集合類:           這個在先前的文章中也用到了,他們的出現不再讓我們過多的關注同步細節。

②  輕量級同步機制:      相對于老版本中那些所謂的重量級同步機制而言,新的機制更加節省cpu的額外開銷。

關于并發集合類沒什麼好講的,如果大家熟悉非線程安全的集合,那麼這些并發的集合對你來說小菜一碟,這一篇和下一篇我們仔細來玩玩這

些輕量級的同步機制。

一:barrier(屏障同步)

1:基本概念

    msdn對它的解釋是:使多個任務能夠采用并行方式依據某種算法在多個階段中協同工作。乍一看有點不懂,沒關系,我們采取提幹法。

”多個任務“,”多個階段”,“協同”,仔細想想知道了,下一階段的執行必須等待上一個階段中多task全部執行完,那麼我們實際中有這樣

的需求嗎?當然有的,比如我們資料庫中有100w條資料需要導入excel,為了在資料庫中加速load,我們需要開多個任務去跑,比如這

裡的4個task,要想load産品表,必須等4個task都跑完使用者表才行,那麼你有什麼辦法可以讓task為了你兩肋插刀呢?它就是barrier。

8天玩轉并行開發——第四天 同步機制(上)

好,我們知道barrier叫做屏障,就像下圖中的“紅色線”,如果我們的屏障設為4個task就認為已經滿了的話,那麼執行中先到的task必須等待

後到的task,通知方式也就是barrier.signalandwait(),屏障中線程設定操作為new barrier(4,(i)=>{})。

8天玩轉并行開發——第四天 同步機制(上)

啰嗦了半天,還是上下代碼說話:

8天玩轉并行開發——第四天 同步機制(上)

2:死鎖問題

    先前的例子我們也知道,屏障必須等待4個task通過signalandwait()來告知自己已經到達,當4個task全部達到後,我們可以通過

barrier.participantsremaining來擷取task到達狀态,那麼如果有一個task久久不能到達那會是怎樣的情景呢?好,我舉個例子。

8天玩轉并行開發——第四天 同步機制(上)

我們發現程式在加載user表的時候卡住了,出現了類似死循環,這句spinwait.spinuntil(() => barrier.participantsremaining == 0)中

的participantsremaining==0 永遠也不能成立,導緻task0永遠都不能退出,然而barrier還在一直等待task0調用signalandwait來結束屏障。

結果就是造成了互相等待的尴尬局面,我們下個斷點看看情況。

8天玩轉并行開發——第四天 同步機制(上)

3:逾時機制

    當我們coding的時候遇到了這種問題還是很糾結的,是以我們必須引入一種“逾時機制”,如果在指定的時候内所有的參與者(task)都

沒有到達屏障的話,我們就需要取消這些參與者的後續執行,幸好signalandwait給我們提供了逾時的重載,為了能夠取消後續執行,我們

還要采用cancellationtoken機制。

8天玩轉并行開發——第四天 同步機制(上)

二:spinlock(自旋鎖)

    我們初識多線程或者多任務時,第一個想到的同步方法就是使用lock或者monitor,然而在4.0 之後給我們提供了另一把武器spinlock,

如果你的任務持有鎖的時間非常短,具體短到什麼時候msdn也沒有給我們具體的答案,但是有一點值得确定的時,如果持有鎖的時候比較

短,那麼它比那些重量級别的monitor具有更小的性能開銷,它的用法跟monitor很相似,下面舉個例子,add2方法采用自旋鎖。

8天玩轉并行開發——第四天 同步機制(上)