簡體   English   中英

如何同時從BlockingCollection中獲取項目?

[英]How to concurrently take items from the BlockingCollection?

我有一個整數的BlockingCollection 下面是我嘗試開發的代碼,用於從BlockingCollection同時刪除項目。

static void Produce()
    {
        for (int i = 0; i < 100000; i++)
        {
            bc3.Add(i);
        }
        Run();
    }

    static void Run()
    {
        for (int i = 0; i < 5; i++)
        {
            Task.Factory.StartNew(Process, TaskCreationOptions.LongRunning);
        }
    }

    static void Process()
    {
        var stopWatch = new Stopwatch();
        stopWatch.Start();
        while (bc3.Count!= 0)
        {
            bc3.Take();
        }
        stopWatch.Stop();
        Console.WriteLine("Thread {0}",
        Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine("Elapsed Time {0}", stopWatch.Elapsed.Seconds);

    }

這是通過創建5個任務以更快的方式刪除項目的正確方法嗎?

秒表問題

您使用的測量結果是錯誤的

stopWatch.Elapsed.Seconds

代替

stopWatch.ElapsedMilliseconds

您僅顯示秒,但忽略分鍾,小時等。

並發問題

不,這不是從BlockingCollection中刪除項目的正確方法。 無效的陳述是

bc3.Count != 0

所有5個任務都可以同時檢查此條件,發現還剩下1個項目。 他們全部5去

bc3.Take();

一個任務能夠刪除該項目,其他四個任務正在等待。

解決此問題的一種方法是添加

bc3.CompleteAdding();

Produce()

垃圾回收問題

第一個任務完成后, Run()方法完成,並且該方法中的所有任務超出范圍並被垃圾回收。 這可能使您僅看到1條而不是5條完成消息。

要解決此問題,請使用

    static void Run()
    {
        var tasks = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            tasks.Add(Task.Factory.StartNew(Process, TaskCreationOptions.LongRunning));
        }
        try
        {
            Task.WaitAll(tasks.ToArray());
        }
        catch (AggregateException)
        { }        
    }

同步成本

這是我的5個任務(和100000000個項目)的輸出之一:

Thread 11
Thread 13
Thread 12
Thread 14
Thread 15
Elapsed Time 12878
Elapsed Time 13122
Elapsed Time 13128
Elapsed Time 13128
Elapsed Time 13128
Run: 13140

將此與單個任務進行比較:

Thread 12
Elapsed Time 10147
Run: 10149

這是因為只有一個Take()方法可以刪除項目,並且同步需要花費更多時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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