[英]What is the proper way to take an item from a 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.