The asynchronous (non-blocking) alternative of the BlockingCollection<T>
is the Channel<T>
class. It offers almost the same functionality, plus some extra features. You can instantiate a Channel<T>
using the Channel
's static factory methods, as shown below (demonstrating the default values of all available options).
Channel<Item> channel = Channel.CreateUnbounded<Item>(new UnboundedChannelOptions()
{
SingleWriter = false,
SingleReader = false,
AllowSynchronousContinuations = false,
});
Channel<Item> channel = Channel.CreateBounded<Item>(new BoundedChannelOptions(capacity)
{
SingleWriter = false,
SingleReader = false,
AllowSynchronousContinuations = false,
FullMode = BoundedChannelFullMode.Wait,
});
The most striking difference is that the Channel<T>
exposes a Writer
and a Reader
facade. So you can pass the Writer
facade to a method that plays the role of the producer, and similarly the Reader
facade to a method that plays the role of the consumer. The Writer
is only allowed to add items in the channel, and mark it as completed. The Reader
is only allowed to take items from the channel, and await its completion. Both facades expose only non-blocking APIs. For example the ChannelWriter<T>
has a WriteAsync
method that returns a ValueTask
. If you have some reason to block on these APIs, for example if one worker of your producer/consumer pair has to be synchronous, then you can block with .AsTask().GetAwaiter().GetResult()
, but this will not be as efficient as using a BlockingCollection<T>
. If you want to learn more about the similarities and differences between the Channel<T>
and BlockingCollection<T>
classes, take a look at this answer.
An implementation of a custom AsyncBlockingCollection<T>
class, having only the most basic features, can be found in the 3rd revision of this answer.
await Task.Run(() => blockingCollection.Take())
the task will be perform on other thread and your UI thread won't blocked.Isn't that the point? – FlamencoTask
-based API. It can be used from ASP.NET, for example. The code in question would not scale well there. – UntutoredConfigureAwait
was used after theRun()
? [ed. never mind, I see what you're saying now] – Corinthians