国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Lock,LockFree,MemoryBarrier,ConcurrentCollection

2019-11-17 03:18:43
字體:
來源:轉載
供稿:網友

Lock,LockFree,MemoryBarrier,ConcurrentCollection

最近看并行編程書本的一些心得,簡單記錄下多線程和并行編程必知必會的幾個概念,再次加深自己的理解。

.NET Framework4提供了一個新的命名空間System.Collections.Concurrent用于解決常用集合在并發情況下的線程安全問題(ps:通過這個命名空間還可以訪問用于并行化循環和PLINQ的自定義分區器Partitioner)。這個命名空間下的所有線程安全集合都在某種程度上使用了無鎖技術。也就是說,這些集合通過使用比較并交換(Compare And Swap,CAS)指令和內存屏障(Memory Barrier),避免了使用典型的互斥的重量級的鎖,雖然實際開發中對性能要求不高的業務系統中加鎖可以獲得最經濟實惠的開發效益。

一、鎖

在多線程和并發這兩個主題下從來都離不開鎖的身影,鎖是用來做并發最簡單但是代價也可能是最高的方式,在某些場景下加鎖是非常經濟實惠的解決方案。

鎖很好用,代碼也極好維護,但是必須清楚不能濫用,否則可能導致嚴重性能問題。因為加鎖會增加系統內核態與用戶態之間的切換開銷以及線程調度開銷。我們知道,加鎖、釋放鎖會導致上下文切換和調度延時,等待鎖的線程會被掛起直至鎖釋放。內核態的鎖需要操作系統進行一次上下文切換,在上下文切換的時候,cpu之前緩存的指令和數據都將失效,對性能影響最大。

1、使用鎖的三大基本原則

a、不使用鎖

b、使用小粒度的鎖,常見的鎖如互斥鎖(lock)、讀寫鎖(ReaderWriterLockSlim,ReaderWriterLock)等等

c、鎖住盡可能短的時間

2、同步對象

為了封裝鎖的邏輯,通常需要一個同步對象。比如常見的簡單粗暴的同步代碼里,lock(sth)的sth就是一個同步對象。

同步對象必須是引用類型(字符串通常不適合做同步對象,想想為什么),而且它通常是私有的,通常是一個instance或者static field。

為了精確的控制鎖的scope和粒度,我們通常會創建一個dedicated字段,比如locker,asyncObj等;

避免使用lock(this) 或者lock(typeof(sometype))或者lock(string),這種使用方法將無法封裝鎖的邏輯,難以避免死鎖和過度的阻塞,甚至在一個進程內還會溢出app domain邊界。

3、如何減少鎖?

如果你的設計為了復用而有很多共享數據,那么在多線程高并發環境下使用Lock還是LockFree的同步算法都是不可避免的。

根據經驗,當我們需要訪問共享的可寫字段時,通常就可以通過鎖來同步。

為了減少鎖,我們需要減少共享數據的使用。

二、CAS

1、基本原理

CAS,簡單說來就是比較并交換,大致邏輯就是如果A與B相等,那么將C賦值給A。

CAS 操作包含三個操作數:內存位置(V)、預期原值(A)和新值(B)。

如果內存位置的值V與預期原值A相匹配,那么處理器會自動將該位置值更新為新值B;否則,處理器不做任何操作。

2、內部實現偽代碼

bool CAS(T* ptr, T expected, T fresh){    if(*ptr != expected)         return false;    *ptr = fresh;    return true;}

3、優點

CAS是CPU指令級的操作,看上去只有一步原子操作,避免了請求操作系統來裁定鎖的問題,所以一般很快。CAS操作是基于共享數據不會被修改的假設,當同步沖突出現的機會很少時,這種假設就能帶來較大的性能提升。主要優點如下:

a、避免通常加鎖所導致的嚴重性能開銷,減少了內核態與用戶態之間的切換開銷以及線程調度開銷;

b、實現更細力度的并行控制,提高系統吞吐量,有些情況下可以達到成倍的關鍵業務的性能提升。

4、缺點

CAS雖然有明顯的優點,但天下沒有免費的午餐 ,通過CAS實現的LockFree也存在很多問題,比如:a、與硬件體系結構的內存讀寫模型相關,所以存在移植問題b、實現復雜,其正確性很難被證明 (a)、受限于CPU指令 (b)、即使簡單的數據結構也要通過復雜的算法來實現 (c)、ABA問題c、代碼難以維護d、存在活鎖(livelock)問題

所謂活鎖,簡單來講就是指事物1可以使用資源,但它讓其他事物先使用資源;事物2可以使用資源,但它也讓其他事物先使用資源,于是兩者一直謙讓,結果兩者都無法使用資源。

三、MemoryBarrier

為什么需要MemoryBarrier(內存屏蔽),MSDN的解釋是:

MemoryBarrier is required only on multiprocessor systems with weak memory ordering (for example, a system employing multiple Intel Itanium PRocessors).

Synchronizes memory access as follows: The processor executing the current thread cannot reorder instructions in such a way that memory accesses prior to the call to MemoryBarrier execute after memory accesses that follow the call to MemoryBarrier.

簡單來說就是多核處理器會對運行CPU指令順序重排優化,而編譯后的程序可能因為編譯器優化或者計算機硬件結構比如分布式系統等諸多原因,不以編碼時的順序執行,從而引發預期外的問題。

Memory Barrier就是一種在底層保證語句按順序執行的解決方案,調用Thread.MemoryBarrier()之后的代碼中內存訪問不能在這之前就完成了,也就是它可以限制指令重排和內存讀寫的緩存。

參考:

http://stackoverflow.com/questions/3556351/why-we-need-thread-memorybarrier

Barrier類,允許多個任務同步它們不同階段上的并發工作。

四、并行集合

System.Collections.Concurrent命名空間下主要的線程安全并行集合有如下幾種:

1、ConcurrenctQueue<T>

ConcurrenctQueue是System.Collections.Queue的并發版本。它是一個FIFO(Fisrt In,First Out,先進先出)的集合。

ConcurrenctQueue是完全無鎖的,但是當CAS操作失敗且面臨資源爭用的時候,它可能會自旋并且進行重試操作。

2、ConcurrenctStack<T>

ConcurrenctStack是System.Collections.Stack的并發版本。它是一個LIFO(Lastt In,First Out,后進先出)的集合。

ConcurrenctStack是完全無鎖的,但是當CAS操作失敗且面臨資源爭用的時候,它可能會自旋并且進行重試操作。

3、ConcurrenctBag<T>

ConcurrenctBag提供了一個無序的對象集合,而且支持對象重復,當不用考慮順序時非常有用。

ConcurrenctBag使用了很多不同的機制,最大程度地減少了同步的需求以及同步所帶來的開銷。

ConcurrenctBag為每一個訪問集合的線程維護了一個本地隊列,而且在可能的情況下,它會以無鎖的方式訪問這個本地隊列。

ConcurrenctBag在同一個線程添加元素(生產)和刪除元素(消費)的場合下效率非常高。然而,ConcurrenctBag有時候會用到鎖,因此,在生產者和消費者線程完全分開的場景下效率非常低下。

4、ConcurrenctDictionary<TKey,TValue>

ConcurrenctDictionary與經典的鍵值對的字典類似,提供了并發的鍵值訪問。它是System.Collections.IDictionary實現的并發版本。

ConcurrenctDictionary對于讀操作是完全無鎖的,它對于需要頻繁使用讀取的操作進行了優化。

當很多任務或者線程在字典中添加或者修改數據的時候,ConcurrenctDictionary會使用細粒度的鎖。

5、 BlockingCollection<T>

BlockingCollection與經典的阻塞隊列數據結構類似,它是對一個IProducerConsumerCollection<T>實例的包裝器,提供了阻塞(block)和限界(bound)的能力。

BlockingCollection能夠適用于有多個任務添加和刪除數據的生產者-消費者的情形。

這里再順帶提一下IProducerConsumerCollection<T>這個接口,它繼承自IEnumerable<T>、ICollection和IEnumerable。忍不住要為IProducerConsumerCollection<T>、IEnumerable<T>、ICollection和IEnumerable這幾個接口的抽象拍手叫好。可以說,MS對集合的設計是非常富有遠見并適應變化的。

PS:關于并行集合和線程安全,很久之前我也寫過總結,可以參考之前的拙文淺析線程安全容器的實現。

參考:

<<C#并行編程高級教程>>

http://msdn.microsoft.com/zh-cn/library/system.collections.concurrent(v=vs.110).aspx

http://msdn.microsoft.com/zh-cn/library/dd267312(v=vs.110).aspx

http://blog.hesey.net/2011/09/resolve-aba-by-atomicstampedreference.html


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 扶余县| 新安县| 都安| 正定县| 峨眉山市| 双辽市| 渭南市| 京山县| 蕲春县| 乐都县| 方城县| 临澧县| 安乡县| 呼和浩特市| 淳安县| 宿松县| 文化| 永寿县| 宁明县| 牡丹江市| 中西区| 洛扎县| 沙洋县| 东明县| 陆丰市| 通州区| 建平县| 威海市| 五寨县| 广平县| 阿拉善左旗| 马鞍山市| 宿松县| 德钦县| 孟州市| 新巴尔虎左旗| 固安县| 蓬莱市| 曲松县| 乐业县| 三亚市|