Channel is async: no thread blocks while waiting, unlike BlockingCollection.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // ====================================================================== // Q: How do you implement producer/consumer? Why Channel<T>? // // - Channel is async: no thread blocks while waiting, unlike BlockingCollection. // - Bounded = backpressure, so memory doesn't fill up if the consumer is slow. // Unbounded only when the rate is under control. // - It is in-process: if the process dies, the messages are lost. Anything that // must not be lost goes to an outbox + broker (Q30). // ====================================================================== var channel = Channel.CreateBounded<OrderEvent>(new BoundedChannelOptions(1_000) { FullMode = BoundedChannelFullMode.Wait // backpressure: the producer waits when it is full }); // Producer (e.g. an endpoint) await channel.Writer.WriteAsync(evt, ct); // Consumers: 4 workers reading in parallel (e.g. inside a BackgroundService) var workers = Enumerable.Range(0, 4).Select(_ => Task.Run(async () => { await foreach (var e in channel.Reader.ReadAllAsync(ct)) await HandleAsync(e, ct); })); await Task.WhenAll(workers); |