-1

I am trying to ascertain why performance on my blocking collection appears slow. A simple version of my code is illustrated in the question further below.

My question here is if BlockingCollection.TryTake(object,TimeSpan) returns immediately on new data?

TimeSpan gridNextTS = new TimeSpan(0, 0, 60);

if (trPipe.TryTake(out tr, gridNextTS) == false)

From my testing it appears that data is NOT returned immediately. Does that seems likely desired behaviour or am I using it incorrectly?

Detail of code previous question:

Consumer/Producer with BlockingCollection appears slow

Community
  • 1
  • 1
ManInMoon
  • 6,795
  • 15
  • 70
  • 133
  • 3
    What do you mean by "immediately"? (A short but *complete* program demonstrating the problem would really help.) – Jon Skeet Jul 14 '14 at 10:02

1 Answers1

4

A concise benchmark shows that BlockingCollection<T> does, in fact, perform the handover pretty swiftly regardless of the timeout value supplied to TryTake.

public async Task BlockingCollectionPerformance()
{
    using (var collection = new BlockingCollection<int>())
    {
        var consumer = Task.Run(() =>
        {
            var i = 0;

            while (collection.TryTake(out i, TimeSpan.FromSeconds(2)))
            {
                Debug.Print(i.ToString());
            }
        });

        var producer = Task.Run(() =>
        {
            try
            {
                for (var i = 0; i < 10; i++)
                {
                    collection.Add(i);
                }
            }
            finally
            {
                collection.CompleteAdding();
            }
        });

        await Task.WhenAll(producer, consumer);
    }
}

The above completes in ~3 ms on my box.

To be more specific though, TryTake returns quickly whenever an item is added to the collection (and TryTake returns true), or when you call CompleteAdding on the blocking collection (in which case there is no point in waiting out the timeout, and TryTake returns false). It is possible to shoot yourself in the foot by keeping the consumer blocked longer than necessary if you never call CompleteAdding in which case TryTake will have to wait out the full timeout length before returning false.

Kirill Shlenskiy
  • 9,367
  • 27
  • 39
  • Apologies for the `TryAdd`s in the original version: that was a typo. – Kirill Shlenskiy Jul 14 '14 at 10:27
  • I get hundreds of thousands of Add events every day. Should I call CompleteAdding after each? – ManInMoon Jul 14 '14 at 11:08
  • @ManInMoon, only if you use hundreds of thousands of blocking collections (which you probably don't). CompleteAdding needs to be called once - when you're done with the collection and won't ever add to it again. The main point is - blocking collection is fast (for what it does), so look for your bottleneck elsewhere. – Kirill Shlenskiy Jul 14 '14 at 11:19
  • Thank you. Blockage was elsewhere. I am not calling CompleteAdding at all ,because the Collection is constantly updated during the day. You are correct, the footprint is very small and I can run through several million Add/TryTake cycles in a very short period. Many thanks – ManInMoon Jul 15 '14 at 09:09
  • @ManInMoon, glad to hear you worked it out in the end. – Kirill Shlenskiy Jul 15 '14 at 12:10