System.Threading.Channels
Learn producer-consumer flow with Channel<T>.
What is System.Threading.Channels?
System.Threading.Channels is a useful construct for producer-consumer scenarios. A channel queues items that the producer writes; the consumer reads them in order. Production and consumption can run at different speeds.
Creating a channel: var channel = Channel.CreateUnbounded<int>();. An unbounded channel accepts all items. For a bounded channel use CreateBounded<int>(10); it holds at most 10 items. The producer uses channel.Writer.WriteAsync(...); the consumer uses channel.Reader.ReadAsync().
Producer/Consumer
While the producer writes to the channel, the consumer reads in parallel. The producer uses await channel.Writer.WriteAsync(item);; the consumer uses var item = await channel.Reader.ReadAsync();. When done, the producer calls channel.Writer.Complete();.
The consumer exits its read loop when the channel is empty and the writer is Complete. This is a clean way to build a concurrent work queue. You can wait for items with WaitToReadAsync.
Exercise Producer-consumer with a channel
Make Main a static async Task Main. Create a channel with var channel = Channel.CreateUnbounded<int>();. Write two items with await channel.Writer.WriteAsync(10); and await channel.Writer.WriteAsync(20);. Finish writing with channel.Writer.Complete();. Sum all items with int sum = 0; await foreach (int n in channel.Reader.ReadAllAsync()) { sum += n; } and print with Console.WriteLine(sum);.
Show example solution
Make Main static async Task Main() and write var channel = Channel.CreateUnbounded<int>(); await channel.Writer.WriteAsync(10); await channel.Writer.WriteAsync(20); channel.Writer.Complete(); int sum = 0; await foreach (int n in channel.Reader.ReadAllAsync()) { sum += n; } Console.WriteLine(sum);
Example solution:
using System;
using System.Collections.Generic;
using System.Threading.Channels;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var channel = Channel.CreateUnbounded<int>();
await channel.Writer.WriteAsync(10);
await channel.Writer.WriteAsync(20);
channel.Writer.Complete();
int sum = 0;
await foreach (int n in channel.Reader.ReadAllAsync())
{
sum += n;
}
Console.WriteLine(sum);
}
}
Test yourself
-
Create a channel
var channel = Channel.____<int>();Show answer
var channel = Channel.CreateUnbounded<int>(); -
When are Channels used?
- Only in single-threaded code
- Instead of sync foreach
- For catching exceptions
- When producer and consumer run at different speeds
Show answer
When producer and consumer run at different speeds — Correct. Channels are ideal for producer-consumer scenarios.
-
Match channel concepts
- Channel.CreateUnbounded
- Unbounded channel
- Writer.WriteAsync
- Writes an item
- Reader.ReadAsync
- Reads an item
- Writer.Complete
- Finishes writing