CodeBlanks Logo Icon CodeBlanks

Summary - Channels

C# course · Expert · Lesson 36/47

Combine ChannelWriter, ChannelReader and Complete to write a log processor.

Summary - Channels

In this summary you will write a log processor. The producer writes log lines into the channel and closes it with Complete; the consumer reads each log with ReadAllAsync, splits by level and counts.

The methods from earlier lessons (CreateUnbounded, WriteAsync, Complete, ReadAllAsync and OrderBy) all come together here. A single-threaded async flow keeps the output deterministic.

Log processor design

The producer writes three logs: "INFO: started", "WARN: slow", "ERROR: fail". Then Complete is called. The consumer reads each log with await foreach, extracts the level name with Split(':')[0] and counts in a Dictionary.

Results are printed alphabetically with OrderBy(k => k.Key). Since the levels differ, each count is 1.

Exercise Assemble the log processor

channel is an unbounded string channel. Write three logs with await channel.Writer.WriteAsync: "INFO: started", "WARN: slow", "ERROR: fail". Call channel.Writer.Complete(). In a Dictionary<string, int>, count each log's level (log.Split(':')[0]) with await foreach (var log in channel.Reader.ReadAllAsync()). Then print $"{kvp.Key}: {kvp.Value}" sorted by OrderBy(k => k.Key). Make Main async Task.

Show example solution
')[0]] = counts.GetValueOrDefault(...) + 1. Print with OrderBy(k => k.Key).
Example solution:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Channels;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var channel = Channel.CreateUnbounded<string>();
        var counts = new Dictionary<string, int>();
        await channel.Writer.WriteAsync("INFO: started");
        await channel.Writer.WriteAsync("WARN: slow");
        await channel.Writer.WriteAsync("ERROR: fail");
        channel.Writer.Complete();
        await foreach (var log in channel.Reader.ReadAllAsync())
        {
            var level = log.Split(':')[0];
            counts[level] = counts.GetValueOrDefault(level) + 1;
        }
        foreach (var kvp in counts.OrderBy(k => k.Key))
        {
            Console.WriteLine($"{kvp.Key}: {kvp.Value}");
        }
    }
}

Test yourself

  1. Complete the WriteAsync call

    await channel.Writer.____;
    Show answer
    await channel.Writer.WriteAsync("log: error");
  2. What does the producer do in a log processor?

    • Reads logs
    • Filters logs
    • Writes logs to the channel
    • Deletes logs
    Show answer

    Writes logs to the channel — Correct. The producer writes logs with WriteAsync.

  3. Match each log processor step

    CreateUnbounded
    Create the channel
    Writer.WriteAsync
    Produce a log
    Writer.Complete
    End production
    Reader.ReadAllAsync
    Consume logs

All lessons in Expert