[英]ConcurrentBag - Add Multiple Items?
有沒有辦法一次向 ConcurrentBag 添加多個項目,而不是一次添加一個? 我在 ConcurrentBag 上沒有看到 AddRange() 方法,但是有一個 Concat()。 但是,這對我不起作用:
ConcurrentBag<T> objectList = new ConcurrentBag<T>();
timeChunks.ForEach(timeChunk =>
{
List<T> newList = Foo.SomeMethod<T>(x => x.SomeReadTime > timeChunk.StartTime);
objectList.Concat<T>(newList);
});
此代碼曾經位於 Parallel.ForEach() 中,但我將其更改為上述代碼,以便對其進行故障排除。 變量 newList 確實有對象,但是在 objectList.Concat<> 行之后,objectList 中總是有 0 個對象。 Concat<> 不是這樣工作的嗎? 我是否需要使用 Add() 方法一次向 ConcurrentBag 添加一個項目?
(我知道這是一個舊帖子,我想我會添加一些東西)。
就像其他人說的:是的,您需要將它們一一添加。 在我的例子中,我添加了一個小的擴展方法來使事情更簡潔,但在引擎蓋下它做同樣的事情:
public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd)
{
foreach (var element in toAdd)
{
@this.Add(element);
}
}
接着:
ConcurrentBag<int> ccBag = new ConcurrentBag<int>();
var listOfThings = new List<int>() { 1, 2, 4, 5, 6, 7, 8, 9 };
ccBag.AddRange(listOfThings);
我還研究了使用 AsParallel 在擴展方法中添加,但是在對添加各種大小的字符串列表進行了一些測試之后,與傳統的 for 循環相比,使用 AsParallel(如此處所示)的速度始終較慢。
public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd)
{
toAdd.AsParallel().ForAll(t => @this.Add(t));
}
Concat
是 LINQ 提供的擴展方法。 它是一個不可變的操作,它返回另一個IEnumerable
,它可以枚舉源集合,緊接着是指定的集合。 它不會以任何方式更改源集合。
您需要一次將您的項目添加到ConcurrentBag
。
我遇到了類似的問題,試圖並行處理較小的數據塊,因為一大塊使我用來在發送端訪問我的數據的 Web 服務超時,但我不希望通過處理每個塊來使運行速度變慢連續。 按記錄處理數據記錄甚至更慢 - 由於我調用的服務可以處理批量請求,因此最好在不超時的情況下提交盡可能多的請求。
就像 Vlad 所說,將並發包連接到對象類型的列表不會返回並發包,因此 concat 將不起作用! (我花了一段時間才意識到我不能這樣做。)
試試這個 - 創建一個List<T>
,然后創建一個ConcurrentBag<List<T>>
。 在每次並行迭代中,它將向並發包添加一個新列表。 並行循環完成后,循環遍歷ConcurrentBag
和 concat(如果您想消除可能的重復,則為 union)到您創建的第一個List<T>
以將所有內容“展平”到一個列表中。
Concat
方法是包含在支持System.Linq
庫(內部.NET System.Core
程序集)的公共Enumerable
靜態類中的一種方法。
但是, Concat
包含向ConcurrentBag<T>
對象提供“添加范圍”要求的限制,其行為如下圖所示(在 Visual Studio 中的第 47 行):
為了使Concat
方法符合“添加范圍”的要求,需要更新當前的ConcurrentBag<T>
對象實例; 如果程序需要添加多個范圍,則需要為每個范圍從當前ConcurrentBag<T>
(遞歸)創建自動引用實例。
然后,我不使用Concat
方法,如果我可以提出建議,我不推薦。 我遵循Eric的回答中的一個類似示例,在該示例中,我從ConcurrentBag<T>
開發了一個派生類,該類為我提供了 AddRange 方法,使用ConcurrentBag<T>
基方法將IEnumerable<T>
項添加到派生實例,如下所示:
public class ConcurrentBagCompleted<T> : ConcurrentBag<T> { public ConcurrentBagCompleted() : base() { } public ConcurrentBagCompleted(IEnumerable<T> collection):base(collection) { } public void AddRange(IEnumerable<T> collection) { Parallel.ForEach(collection, item => { base.Add(item); }); } }
是的 :)
Concat
可能是Enumerable
擴展之一。 它不會向ConcurrentBag
添加任何內容,它只是返回一些包含原始包以及您嘗試添加的任何內容的時髦對象。
請注意Concat
的結果不再是ConcurrentBag
,因此您不會想要使用它。 它是通用 LINQ 框架的一部分,使組合不可變序列成為可能。 當然,該框架不會嘗試將操作數的並發屬性擴展到結果,因此結果對象將不太適合多線程訪問。
(基本上, Concat
適用於ConcurrentBag
因為它公開了IEnumerable<T>
接口。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.