首頁 培訓計劃 培訓課程 企業內訓 學員論壇 技術文章 成功案例 師資簡介 關于我們 在線留言  
行業新聞
.NET的枚舉并發集合探討

文章來源:http://www.kuqin.com/dotnet/20080905/16657.html 作者: 發布日期:2010-04-27
打 印】【關 閉

.NET的并行擴展(Parallel Extensions)包括兩個并發集合:堆棧和隊列。其他集合類還是按照它們固有的方式工作,但是對于語義的處理依然有一些揮之不去的問題。尤其是當集合在一個線程被編輯,而在另外一個線程被枚舉的時候,會發生什么呢?

對于單線程的類,答案是眾所周之的,枚舉器將拋出一個異常。不過對于并發類來說,在這種情況下應該設定一種規則,提供幾種選擇。

一種選擇是,在枚舉開始的時候為現存數據創建一個快照。這種方式在循環的過程中會占用更多的內存,不過快照一旦被創建,就可以被自由地鎖定。這種方式下隱含的性能問題很難被預估。

不使用快照,集合還有一組保證措施提供給開發人員。它們中很多都是自相矛盾的,不過在某些條件下它們也都是適合的。

  • 刪除的條目總是可讀
  • 刪除的條目不可再讀
  • 如果添加在集合的末尾,那么添加的條目總是可讀
  • 如果添加在集合的任何地方,那么添加的條目總是可讀
  • 添加的條目總是不可讀取
  • 被移動的條目,不能被讀取兩次
  • 被移動的條目,如果是移動到集合的末尾,那么就能被讀取兩次
  • 被移動的條目,就算是被移動到集合的開頭,也總是可以讀取
  • 不超過N條的條目就能被讀取,而N是集合的初始大小。

在給出一個選擇范圍后,Stephen Toub向大家征詢關于并行擴展的反饋意見

  1. 鑒于在.NET中已經存在一些標準的集合類了,假如你已經具有它們的線程安全(thread-safe)版本,那么什么樣的情形下,你才可以從能并發地枚舉同一個被其它線程同時編輯的集合中獲得好處?我們雖然對此已經有所了解,不過還是很想多聽聽大家的意見。
  2. 假設你確實具有第一條提到的情形,那么為了讓從枚舉器中返回的數據是可用的,你大概需要的最小保證措施是什么?例如,對于一個字典對象如果不存在并發編輯(添加/更新/刪除),你可以認為它是線程安全的,你將能在枚舉過程中準確地得到字典中的內容;然而,如果存在并發訪問,你再也不能得到已經不存在于字典中的內容,你可能看不到并發添加或更新的東西,也可能依然能看到那些被并發地刪除的條目。
  3. 如果我們確實支持在線程安全的集合上進行面向并發編輯的枚舉操作,那么你希望能夠從“在并發編輯上拋出異常”這樣的行為中恢復之前的操作嗎?
  4. 最后,你期望看到的既線程安全又能實現可伸縮副本的集合中,哪個最重要?

Omer van Kloeten對于序列化,提出了一個重要的問題,

一個重要的附加功能是能夠異步地轉儲(dump),即有時為了備份可以把內存的數據緩存到持久性存儲,這就要求線程安全的枚舉過程。(實際上,想一想——是否也能線程安全地序列化?這樣的話什么才是默認的行為呢?)

Rick Brewster則建議我們求助于函數式編程概念。代替在外部鎖定集合的方式,所有對集合的并發操作都能通過給“Lock(Action)”方法傳遞一個委托來執行.

這個點子就是讓“Lock”方法自動地用lock/unlock這樣的結構把你的回調包圍起來。這種方法也不會限制你使用這些類當前已經暴露出來的原子操作。實際上,也許讓Lock來獲得Func而非Action更好,并且ConcurrentList類本身不真正具有任何用于get、set、enumerate的方法。使用這種方式,你就只能訪問在鎖定范圍內的類。

查看英文原文:Enumerating Concurrent Collections
來自:http://www.infoq.com/cn/news/2008/09/Parallel-Enumerators

打 印】【關 閉

上一篇:對誰失去了信心?是.NET還是微軟
下一篇:在GRIDVIEW中增加一行
相關新聞
版權所有©威課網 粵ICP備13058727號