Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between Take/TryTake and Add/TryAdd on a Blocking Collection

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() ?

like image 678
Muds Avatar asked Jan 17 '18 12:01

Muds


People also ask

How does Blocking collection work?

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.

Is BlockingCollection thread-safe?

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.


3 Answers

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.

like image 192
Backs Avatar answered Oct 16 '22 16:10

Backs


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.

like image 28
Pieter van Ginkel Avatar answered Oct 16 '22 15:10

Pieter van Ginkel


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

like image 1
Kayvan Salimi Avatar answered Oct 16 '22 15:10

Kayvan Salimi