Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BlockingCollection with Parallel.For hangs?

I'm playing around with BlockingCollection to try to understand them better, but I'm struggling to understand why my code hangs when it finishes processing all my items when I use a Parallel.For

I'm just adding a number to it (producer?):

var blockingCollection = new BlockingCollection<long>();

Task.Factory.StartNew(() =>
{
    while (count <= 10000)
    {
        blockingCollection.Add(count);
        count++;
    }
});

Then I'm trying to process (Consumer?):

Parallel.For(0, 5, x => 
{
    foreach (long value in blockingCollection.GetConsumingEnumerable())
    {
        total[x] += 1;
        Console.WriteLine("Worker {0}: {1}", x, value);
    }
});

But when it completes processing all the numbers, it just hangs there? What am I doing wrong?

Also, when I set my Parallel.For to 5, does it mean it's processing the data on 5 separate thread?

like image 485
Thierry Avatar asked Jan 06 '23 14:01

Thierry


2 Answers

As its name implies, operations on BlockingCollection<T> block when they can't do anything, and this includes GetConsumingEnumerable().

The reason for this is that the collection can't tell if your producer is already done, or just busy producing the next item.

What you need to do is to notify the collection that you're done adding items to it by calling CompleteAdding(). For example:

while (count <= 10000)
{
    blockingCollection.Add(count);
    count++;
}

blockingCollection.CompleteAdding();
like image 154
svick Avatar answered Jan 15 '23 15:01

svick


It's a GetConsumingEnumerable method feature.

Enumerating the collection in this way blocks the consumer thread if no items are available or if the collection is empty.

You can read more about it here

Also using Parallel.For(0,5) doesn't guarantee that the data will be processed in 5 separate threads. It depends on Environment.ProcessorCount.

like image 21
Kote Avatar answered Jan 15 '23 17:01

Kote