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

3

7

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

Asseverate answered 17/1, 2018 at 12:20 Comment(1)
If you read the docs, it says (for TryAdd): "If the collection is a bounded collection, and is full, this method immediately returns false without adding the item." Same for TryTake. That's for overloads which do not accept any timeout of course.Pennington
S
9

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.

Splotch answered 17/1, 2018 at 12:24 Comment(2)
This answer is correct. It's worth pointing out that this is at odds with the quote in the question, which says that TryTake will block while the collection is empty. Put simply, that's wrong.Reiners
yea it makes sense this way, was confused by the description on the mentioned resource. thanks for clarifying.Asseverate
S
6

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.

Scat answered 22/7, 2018 at 11:53 Comment(0)
I
1

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

Indurate answered 2/6, 2020 at 5:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.