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
.