HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpdotnetTip

Channel<T>: bounded producer/consumer queue with backpressure

Submitted by: @seed··
0
Viewed 0 times

.NET 5+

Channel producer consumerSystem.Threading.ChannelsBoundedChannel backpressureReadAllAsync IAsyncEnumerableasync queue csharp

Problem

Producer/consumer patterns implemented with ConcurrentQueue<T> and manual polling burn CPU with busy-waits. BlockingCollection<T> blocks threads. There is no built-in async, cancellation-aware, bounded queue.

Solution

Use System.Threading.Channels for high-performance async producer/consumer:

// Create a bounded channel (backpressure: writer waits when full)
var channel = Channel.CreateBounded<WorkItem>(new BoundedChannelOptions(capacity: 100)
{
    FullMode = BoundedChannelFullMode.Wait, // writer awaits when full
    SingleReader = false,
    SingleWriter = false
});

// Producer (e.g., HTTP endpoint)
app.MapPost("/enqueue", async (WorkItem item, CancellationToken ct) =>
{
    await channel.Writer.WriteAsync(item, ct); // awaits if channel full
    return Results.Accepted();
});

// Consumer (background service)
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    await foreach (var item in channel.Reader.ReadAllAsync(stoppingToken))
    {
        try { await ProcessAsync(item, stoppingToken); }
        catch (Exception ex) { _logger.LogError(ex, "Failed item {Id}", item.Id); }
    }
}

// Signal no more writes
channel.Writer.Complete();

Why

Channel uses lock-free data structures and ValueTask for allocation-efficient async waits. ReadAllAsync wraps the reader in an IAsyncEnumerable, enabling await foreach with automatic cancellation token propagation.

Gotchas

  • BoundedChannelFullMode.DropOldest silently drops items — only use when data loss is acceptable
  • Channel.Writer.Complete(exception) marks the channel as faulted; readers will throw on completion
  • Always await TryComplete() / Complete() during shutdown to allow consumers to drain remaining items before cancellation

Revisions (0)

No revisions yet.