SoFunction
Updated on 2025-04-07

Simple usage method for Channel class in .NET

What is Channel for

The namespace provides a set of synchronization data structures for passing data between producers and consumers asynchronously. The library targets .NET Standard and works on all .NET implementations.
Channels are an implementation of the producer/consumer conceptual programming model.
The above is the official explanation from Microsoftchannels. In Chinese, this class provides the ability to asynchronize traditional data between producers and consumers. In short, it can be regarded as a memory message queue.

Example 1

Here is a simple example of how to use the Channel class to create a producer-consumer model:

    static async Task Main(string[] args)
    {
        var channel = <int>();
        var producer = (async () =>
        {
            for (int i = 0; i < 10; i++)
            {
                await (i);
                await (1000); // Simulating the producer takes some time to generate data            }
            ();
        });
        var consumer = (async () =>
        {
            await foreach (var item in ())
            {
                ($"Consumers receive: {item}");
            }
        });
        await (producer, consumer);
    }

In this example, we create an unbounded channel and then create two tasks, one for the producer and the other for the consumer. The producer generates a number per second and then writes it to the channel. The consumer reads the data from the channel and prints it out. When the producer completes writing, it calls () to notify the consumer that there is no more data to read.

Example 2

You can use the (capacity) method to create a bounded channel, where the capacity parameter specifies the capacity of the channel. When the channel is full, the attempted write will block until space is available.

    static async Task Main(string[] args)
    {
        var channel = <int>(5); // Create a bounded channel with a capacity of 5        var producer = (async () =>
        {
            for (int i = 0; i < 10; i++)
            {
                await (i);
                ($"Producer generated: {i}");
                await (1000); // Simulating the producer takes some time to generate data            }
            ();
        });
        var consumer = (async () =>
        {
            await foreach (var item in ())
            {
                ($"Consumers receive: {item}");
                await (2000); // Simulating the consumer takes some time to process the data            }
        });
        await (producer, consumer);
    }

In this example, we create a bounded channel with a capacity of 5. The producer generates a number per second and then writes it to the channel. The consumer reads data from the channel and prints it out, but the consumer processes data slowly than the producer, so when the channel is full, the producer's WriteAsync operation will block until the consumer reads some data, making the channel available.

Example 3

Here is an example showing how to share a channel between multiple producers and consumers:

    static async Task Main(string[] args)
    {
        var channel = <int>();
        // Create two producers        var producer1 = Produce(, id: 1);
        var producer2 = Produce(, id: 2);
        // Create two consumers        var consumer1 = Consume(, id: 1);
        var consumer2 = Consume(, id: 2);
        // Wait for all producers and consumers to complete        await (producer1, producer2, consumer1, consumer2);
    }
    static async Task Produce(ChannelWriter<int> writer, int id)
    {
        for (int i = 0; i < 10; i++)
        {
            await (i);
            ($"Producer{id}Generated: {i}");
            await (1000); // Simulating the producer takes some time to generate data        }
        ();
    }
    static async Task Consume(ChannelReader<int> reader, int id)
    {
        await foreach (var item in ())
        {
            ($"consumer{id}Received: {item}");
            await (2000); // Simulating the consumer takes some time to process the data        }
    }

In this example, we create two producers and two consumers, both sharing the same channel. This is a very important usage pattern. Because when we use message queues, there are often multiple producers and multiple consumers. We can control the amount of data pushed into the queue by controlling the speed of production of producers. We can also control the speed of consumption data by controlling the number of consumers, thereby adjusting the system's flow and achieving the effect of peak reduction and valley filling.

Summarize

The Channel class is a newly added class after .NET CORE 3.0. Provide us with a convenient producer/consumer model implementation solution. It is equivalent to a memory queue in a process, and it is not persisted, pure memory operations, and its performance is very, very high. We can provide throughput to our system when we face true high concurrency. Of course the price is memory and giving up some real-time.

This is all about this article about the simple use of the Channel class in .NET. For more related content on the use of the Channel class, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!