5

What is the difference between solution 1 and 2, _taskQ is BlockingCollection and I am trying to implement a Producer-Consumer scenario. The BlockingCollection uses the default ConcurrentQueue for internal storage.

//Solution 1
foreach (Action action in _taskQ.GetConsumingEnumerable())
{
    action(); // Perform task.
    Thread.Sleep(1000);
}

TryTake blocks when there is no item

//Solution 2
Action t;
while(_taskQ.TryTake(out t))
{
    t();
    Thread.Sleep(1000);
}
Helic
  • 907
  • 1
  • 10
  • 25
  • why not use `System.Threading.Task` and do something like this `Task.Run(async delegate { await Task.Delay(1000); });` – MethodMan Feb 04 '16 at 16:21
  • @MethodMan Why would you delay in the background? Just `await Task.Delay(1000);` – piedar Feb 04 '16 at 16:26
  • 5
    Your assumption is not correct. The iterator will wait until an item shows up in the collection. But TryTake() returns *false* when the collection is empty. Calling Sleep() is never a good way to avoid burning 100% core, you'll like the iterator much better. Delete the Sleep() call. – Hans Passant Feb 04 '16 at 16:27
  • @MethodMan, you mean to replace Thread.Sleep(1000) with Task.Run? Task.Run runs the delegate on the threadpool, so it is not blocking as Thread.Sleep(1000). – Helic Feb 04 '16 at 16:28

1 Answers1

12

bool TryTake(out T) returns false immediately if there are no items.
bool TryTake(out T, TimeSpan) returns false if there are no items within the timeout period. The enumerable returned by GetConsumingEnumerable() blocks while it has no items, until a producer calls CompleteAdding().

In Solution 1, you wait for the next action and execute it; a suitable pattern! But the Thread.Sleep() is not really necessary because the iteration will block if there are no items anyway.

In Solution 2, you take and execute actions while there are any, then exit the loop if the consumer gets ahead of the producer. That's probably not what you want.

piedar
  • 2,599
  • 1
  • 25
  • 37