天天看點

C# 集合-并發處理-鎖OR線程

   每次寫部落格,第一句話都是這樣的:程式員很苦逼,除了會寫程式,還得會寫部落格!當然,希望将來的一天,某位老闆看到此部落格,給你的程式員職工加點薪資吧!因為程式員的世界除了苦逼就是沉默。我眼中的程式員大多都不愛說話,默默承受着程式設計的巨大壓力,除了技術上的交流外,他們不願意也不擅長和别人交流,更不樂意任何人走進他們的内心!

   最近悟出來一個道理,在這兒分享給大家:學曆代表你的過去,能力代表你的現在,學習代表你的将來。我們都知道計算機技術發展日新月異,速度驚人的快,你我稍不留神,就會被慢慢淘汰!是以:每日不間斷的學習是避免被淘汰的不二法寶。

   當然,題外話說多了,咱進入正題!

   背景   

   C#命名空間:System.Collenctions和System.Collenctions.Generic 中提供了很多清單、集合和數組。例如:List<T>集合,數組Int[],String[] ......,Dictory<T,T>字典等等。但是這些清單、集合和數組的線程都不是安全的,不能接受并發請求。下面通過一個例子來加以說明,如下:

   本例中,開辟了三個線程,通過循環向集合中添加資料,每個線程執行1000次(三個線程之間的操作是同時進行的,也是并行的),那麼,理論上結果應該是3000。

   上文中我們講到: C#命名空間:System.Collenctions和System.Collenctions.Generic 下的清單,數組,集合并不能保證線程安全,并不能防止并發的發生。

   本例運作的結果也證明了上述結論的正确性,其結果如下:

C# 集合-并發處理-鎖OR線程

   由此可見:C#命名空間:System.Collenctions和System.Collenctions.Generic 下的清單,數組,集合确實不能保證線程安全,确實不能預防并發。那麼我們應當怎麼解決上述問題呢?

   還好,自C#2.0以來,LOCK是一直存在的。使用LOCK(互斥鎖)是可以做到防止并發的,示例代碼如下:

引入了Lock,運作結果也正常了,如下:

C# 集合-并發處理-鎖OR線程

   但是鎖的引入,帶來了一定的開銷和性能的損耗,并降低了程式的擴充性,而且還會有死鎖的發生(雖說機率不大,但也不能不防啊),是以:使用LOCK進行并發程式設計顯然不太适用。

   還好,微軟一直在更新自己的東西:

   .NET Framework 4提供了新的線程安全和擴充的并發集合,它們能夠解決潛在的死鎖問題和競争條件問題,是以在很多複雜的情形下它們能夠使得并行代碼更容易編寫,這些集合盡可能減少使用鎖的次數,進而使得在大部分情形下能夠優化為最佳性能,不會産生不必要的同步開銷。

   需要注意的是:在串行代碼中使用并發集合是沒有意義的,因為它們會增加無謂的開銷。

   在.NET Framework4.0以後的版本中提供了命名空間:System.Collections.Concurrent 來解決線程安全問題,通過這個命名空間,能通路以下為并發做好了準備的集合。

   1.BlockingCollection 與經典的阻塞隊列資料結構類似,能夠适用于多個任務添加和删除資料,提供阻塞和限界能力。

   2.ConcurrentBag 提供對象的線程安全的無序集合

   3.ConcurrentDictionary  提供可有多個線程同時通路的鍵值對的線程安全集合

   4.ConcurrentQueue   提供線程安全的先進先出集合

   5.ConcurrentStack   提供線程安全的後進先出集合

   這些集合通過使用比較并交換和記憶體屏障等技術,避免使用典型的互斥重量級的鎖,進而保證線程安全和性能。

   ConcurrentQueue 

   ConcurrentQueue 是完全無鎖的,能夠支援并發的添加元素,先進先出。下面貼代碼,詳解見注釋:

   結果如下:

C# 集合-并發處理-鎖OR線程

   從執行時間上來看,使用 ConcurrentQueue 相比 LOCK 明顯快了很多!

   上面的執行個體可以使用ConcurrentBag嗎?當然是可以的啦,因為:ConcurrentBag 和 ConcurrentQueue一樣,操作的對象都是集合,隻不過方式不同罷了!同理:小虎斑們也可以嘗試使用 ConcurrentStack 在這裡,我僅僅貼上使用ConcurrentBag的代碼,如下:

   執行結果如下:

C# 集合-并發處理-鎖OR線程

  對于并發下的其他集合,我這邊就不做代碼案列了!如有疑問,歡迎指正!

   @陳卧龍的部落格

繼續閱讀