I have been trying to get my head around the Blocking Collection and I came across Take()
and TryTake()
also Add()
and TryAdd()
I understand that if there are no items to take, Take()
will wait till an item is added, similarly with Add()
if the collection has reached its max limit, it will wait till the item is removed.
As per Josheph Albahari's article on Parallel Programming
"Add and TryAdd may block if the collection size is bounded; Take and TryTake block while the collection is empty."
So Take()
and TryTake()
both wait for an item to be added. So, if we are not providing any timeout or cancellation token, what is the difference between Take()
and TryTake()
, shouldn't TryTake()
return false
straightaway and not wait ? and same for TryAdd()
?
BlockingCollection<T> provides a GetConsumingEnumerable method that enables consumers to use foreach ( For Each in Visual Basic) to remove items until the collection is completed, which means it is empty and no more items will be added.
The BlockingCollection is a thread-safe collection in which you can have multiple threads add and remove data concurrently. It is represented in . Net through the BlockingCollection class; you can use this class to implement a producer-consumer pattern.
TryTake
does not wait, it immediately returns false
if collection has nothing. Take
will wait for an item.
TryTake:
If the collection is empty, this method immediately returns false.
Take:
A call to Take may block until an item is available to be removed.
Take
will signal completion of the queue by throwing an InvalidOperationException
. This makes debugging a bit hard if you have the exceptions tab configured to throw on caught exceptions.
Because of this, I did try to use TryTake
. It turns out that BlockingCollection<T>.Take
actually does use TryTake
, but with an infinite timeout. So instead of writing this:
while (!queue.IsCompleted)
{
object obj;
try
{
obj = queue.Take();
}
catch (InvalidOperationException)
{
continue;
}
// Do something with obj.
}
You can use TryTake
as follows:
while (!queue.IsCompleted)
{
if (!queue.TryTake(out var obj, Timeout.InfiniteTimeSpan))
continue;
// Do something with obj.
}
Makes the code a lot cleaner and doesn't throw the InvalidOperationException
.
I stumbled upon this question and I think this document of Microsoft is really helpful to figure out what's happening behind the science.
If no item is present, maximum capacity on a bounded collection has been reached, or the timeout period has elapsed, then the TryAdd or TryTake operation returns false. This allows the thread to do some other useful work for a while and then try again later to either retrieve a new item or try to add the same item that could not be added previously.
How to Add and Take Items Individually from a BlockingCollection
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With