CodeBlanks Logo Icon CodeBlanks

System.Threading.Channels

C# course · Advanced · Lesson 23/83

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

  1. Create a channel

    var channel = Channel.____<int>();
    Show answer
    var channel = Channel.CreateUnbounded<int>();
  2. 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.

  3. Match channel concepts

    Channel.CreateUnbounded
    Unbounded channel
    Writer.WriteAsync
    Writes an item
    Reader.ReadAsync
    Reads an item
    Writer.Complete
    Finishes writing

All lessons in Advanced