Open.ChannelExtensions
A set of extensions for optimizing/simplifying System.Threading.Channels usage.
A set of extensions for optimizing/simplifying System.Threading.Channels usage. The project is written primarily in C#, distributed under the MIT License license, first published in 2018. Key topics include: async, channel, channels, dotnet, extensions.
Open.ChannelExtensions
A set of extensions for optimizing/simplifying System.Threading.Channels usage.
Click here for detailed documentation.
Highlights
Read & Write
With optional concurrency levels.
- Reading all entries in a channel.
- Writing all entries from a source to a channel.
- Piping (consuming) all entries to a buffer (channel).
.AsAsyncEnumerable()(IAsyncEnumerable) support for .NET Standard 2.1+ and .NET Core 3+
Special ChannelReader Operations
Filter: reads from the channel until a match is found.Transform: applies a transform function upon successfully reading an item from the channel.Batch: attempts to group items into aList<T>(or aQueue<T>) before being available for reading.Join: combines batches into a single channel.
Installation
nugetInstall-Package Open.ChannelExtensions
Examples
Being able to define an asynchronous pipeline with best practice usage using simple expressive syntax:
csawait Channel .CreateBounded<T>(10) .SourceAsync(source /* IEnumerable<Task<T>> */) .PipeAsync( maxConcurrency: 2, capacity: 5, transform: asyncTransform01) .Pipe(transform02, /* capacity */ 3) .ReadAllAsync(finalTransformedValue => { // Do something async with each final value. });
csawait source /* IEnumerable<T> */ .ToChannel(boundedSize: 10, singleReader: true) .PipeAsync(asyncTransform01, /* capacity */ 5) .Pipe( maxConcurrency: 2, capacity: 3, transform: transform02) .ReadAll(finalTransformedValue => { // Do something with each final value. });
Reading (until the channel is closed)
One by one read each entry from the channel
csawait channel.ReadAll( entry => { /* Processing Code */ });
csawait channel.ReadAll( (entry, index) => { /* Processing Code */ });
csawait channel.ReadAllAsync( async entry => { await /* Processing Code */ });
csawait channel.ReadAllAsync( async (entry, index) => { await /* Processing Code */ });
Read concurrently each entry from the channel
csawait channel.ReadAllConcurrently( maxConcurrency, entry => { /* Processing Code */ });
csawait channel.ReadAllConcurrentlyAsync( maxConcurrency, async entry => { await /* Processing Code */ });
Writing
If complete is true, the channel will be closed when the source is empty.
Dump a source enumeration into the channel
cs// source can be any IEnumerable<T>. await channel.WriteAll(source, complete: true);
cs// source can be any IEnumerable<Task<T>> or IEnumerable<ValueTask<T>>. await channel.WriteAllAsync(source, complete: true);
Synchronize reading from the source and process the results concurrently
cs// source can be any IEnumerable<Task<T>> or IEnumerable<ValueTask<T>>. await channel.WriteAllConcurrentlyAsync( maxConcurrency, source, complete: true);
Filter & Transform
Both of these extensions operate synchronously after an item is read from the channel.
Any predicate or selector function must trap errors of the downstream read will fail and data may not be recoverable.
cs// Filter and transform when reading. channel.Reader .Filter(predicate) // .Where() .Transform(selector) // .Select() .ReadAllAsync(async value => {/*...*/});
Batching
csvalues.Reader .Batch(10 /*batch size*/) // Groups into List<T>. .WithTimeout(1000) // Any non-empty batches are flushed every second. .ReadAllAsync(async batch => {/*...*/});
Joining
The inverse of batching.
csbatches.Reader .Join() // Combines the batches into a single channel. .ReadAllAsync(async value => {/*...*/});
Pipelining / Transforming
Transform and buffer entries
cs// Transform values in a source channel to new unbounded channel. var transformed = channel.Pipe( async value => /* transformation */);
cs// Transform values in a source channel to new unbounded channel with a max concurrency of X. const int X = 4; var transformed = channel.Pipe( X, async value => /* transformation */);
cs// Transform values in a source channel to new bounded channel bound of N entries. const int N = 5; var transformed = channel.Pipe( async value => /* transformation */, N);
cs// Transform values in a source channel to new bounded channel bound of N entries with a max concurrency of X. const int X = 4; const int N = 5; var transformed = channel.Pipe( X, async value => /* transformation */, N); // or transformed = channel.Pipe( maxConcurrency: X, capacity: N, transform: async value => /* transformation */);
Contributors
Showing top 4 contributors by commit count.
