簡體   English   中英

ConcurrentBag - 添加多個項目?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM