2011-06-22 28 views
13

ConcurrentBag將允許多個線程從包中添加和刪除項目。一條線可能會將一件物品添加到包中,然後最終將同一件物品放回原處。它說ConcurrentBag是無序的,但它有多無序?在單個線程中,包就像一個堆棧。無序是指「不喜歡鏈表」嗎?什麼是ConcurrentBag <T>的真實世界使用?

什麼是ConcurrentBag的真實世界使用?

+5

你是什麼意思「是怎麼無序它」?有一個定義的訂單或沒有。這就像在說「貓王怎麼死了?」 –

+0

存儲元素的排序不是客戶的業務。所以從API的角度來看,「無序」總是指枚舉的順序(來自'GetEnumerator'方法)。 –

+3

「未訂購」是指訂單沒有任何保證。當前實現的行爲似乎是,當同一個線程正在添加和刪除時,它的行爲就像一個堆棧,而當一個線程從另一個線程獲取時,它就像一個隊列。但我不會指望這種行爲。有關更多信息,請參閱http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=842。如果順序不重要,並且線程既可以是生產者又可以是消費者,那麼'ConcurrentBag'可以比'ConcurrentQueue'提供更好的性能。 –

回答

3

袋子對於跟蹤實例數量非常有用。例如,如果您想記錄哪些主機爲Web請求提供服務,則可以在開始處理請求時將其IP添加到包中,並在完成後將其刪除。

使用手提包可以讓您一眼就看出您當前正在維修的IP。它也可以讓你快速查詢你是否在服務給定的IP地址。

如果您爲此使用一個集合而不是一個包,那麼來自同一個IP地址的多個併發請求將會破壞您的記錄。

+7

你說把他們的IP添加到包中,然後在完成後將其刪除。如何從包中取出特定物品? –

+2

@Dustin:好問題。我正在考慮[ConcurrentHashMultiset](https://guava-libraries.googlecode.com/svn/tags/release09/javadoc/com/google/common/collect/ConcurrentHashMultiset.html)(Java的「ConcurrentBag」等價物) )當我寫我的答案時,_does_有一個'remove'方法。那麼,我不知道.NET的'ConcurrentBag'類是什麼。 :-P –

+2

沒關係,根據你的回答,我能夠想出一個適用於我自己的真實世界場景。 –

1

任何你只需要跟蹤有什麼,不需要隨機訪問或保證順序的地方。如果您有一個線程可以添加要處理的項目,並且線程可以刪除項目以便處理它們,但如果您不關心按照FIFO順序處理這些項目,那麼併發包可以很好地工作。

+3

真實世界場景... –

1

感謝@Chris Jester-Young我想出了一個很好的現實世界,它實際上適用於我正在開發的項目。

查找 - 過程 - 商店

查找 - 線程1 & 2設定爲發現或刮擦的數據(文件系統,網絡等)。這些結果存儲在ConcurrentBag1中。

過程 - 線程3 & 4被設置爲取出ConcurrentBag1,清潔/轉換/處理數據,然後將結果存儲在ConcurrentBag2。

存儲 - 線程5設置爲從ConcurrentBag2收集結果並將結果存儲在SQL中。

+0

從描述中,這聽起來像使用分層隊列(可能是'ConcurrentQueue'或'BlockingCollection'實例)而不是'ConcurrentBag'類來實現會更好。雖然我可能弄錯了,但類似用法之間似乎有相當多的重疊。 –

12

因爲沒有排序,所以ConcurrentBag比ConcurrentStack/Queue具有性能優勢。它由Microsoft作爲本地線程存儲實現。因此,每個添加項目的線程都會在自己的空間中完成此操作。當檢索它們來自本地存儲的物品時。只有當該線程爲空時,線程纔會從另一個線程存儲中竊取項目。因此,ConcurrentBag不是一個簡單的列表,而是一個分佈式項目列表。並且幾乎沒有鎖定,並且應該在高併發時更好地擴展。

不幸的是在.NET 4.0中出現了性能問題(固定在4.5)看到 http://ayende.com/blog/156097/the-high-cost-of-concurrentbag-in-net-4-0