LimitedConcurrency 3.0.0
dotnet add package LimitedConcurrency --version 3.0.0
NuGet\Install-Package LimitedConcurrency -Version 3.0.0
<PackageReference Include="LimitedConcurrency" Version="3.0.0" />
paket add LimitedConcurrency --version 3.0.0
#r "nuget: LimitedConcurrency, 3.0.0"
// Install LimitedConcurrency as a Cake Addin #addin nuget:?package=LimitedConcurrency&version=3.0.0 // Install LimitedConcurrency as a Cake Tool #tool nuget:?package=LimitedConcurrency&version=3.0.0
.NET utilities for concurrent message processing with configurable degree of parallelism, and per-partition ordering.
dotnet add package LimitedConcurrency
LimitedParallelExecutor
LimitedParallelExecutor
allows to run Task
s with a limited degree of parallelism (i.e. not more than N tasks are run in parallel at any given moment).
Unlike various similar custom TaskScheduler
implementations, it maintains the limited degree of parallelism not only for the synchronous part of the task execution, but for entire asynchronous operation.
async Task Job(int delay, string message)
{
Console.WriteLine($"{message} started");
await Task.Delay(delay).ConfigureAwait(false);
Console.WriteLine($"{message} finished");
}
var executor = new LimitedParallelExecutor(degreeOfParallelism: 2);
executor.Enqueue(() => Job(2000, "Job A"));
executor.Enqueue(() => Job(1000, "Job B"));
executor.Enqueue(() => Job(500, "Job C"));
Output:
Job A started
Job B started
Job B finished
Job C started
Job C finished
Job A finished
Notes
- Executor maintains FIFO order, Tasks are started in the order they were enqueued
- While the executor itself is thread-safe, multi-threaded concurrent clients may need synchronization to ensure correct enqueuing order.
- Executor schedules Tasks via
Task.Run
, i.e. on default thread pool scheduler, to ensure that execution is truly parallel even if passedFunc<Task>
implementations are synchronous and blocking.
ConcurrentPartitioner
Another common requirement in concurrent message processing is "partitioning":
- Every message belongs to exactly one partition key, for example customer name in multi-tenant environment
- Messages with different partition keys may be processed in parallel
- Messages within the same partition key must be processed sequentially (or with a limited max concurrency level)
ConcurrentPartitioner
provides such behavior.
async Task<int> Job(int delay, string message)
{
Console.WriteLine($"{message} started");
await Task.Delay(delay).ConfigureAwait(false);
Console.WriteLine($"{message} finished");
return 0;
}
var partitioner = new ConcurrentPartitioner();
partitioner.ExecuteAsync("partition A", () => Job(100, "Job A1"));
partitioner.ExecuteAsync("partition B", () => Job(100, "Job B1"));
partitioner.ExecuteAsync("partition A", () => Job(100, "Job A2"));
partitioner.ExecuteAsync("partition B", () => Job(100, "Job B2"));
Example output:
Job B1 started
Job A1 started
Job B1 finished
Job A1 finished
Job A2 started
Job B2 started
Job A2 finished
Job B2 finished
Notes
- Unlike
LimitedParallelExecutor
, this partitioner does not guarantee FIFO order across multiple partitions (note that B1 may be started before A1)- However, FIFO order is guaranteed within a single partition key
- Just like with
LimitedParallelExecutor
, FIFO order is guaranteed when the clients synchronize access to the synchronous part ofExecuteAsync
- You can specify custom per partition concurrency limit via
ConcurrentPartitioner
's constructor.- This allows to implemented "keyed limiter" scenarios, e.g. executing not more than N concurrent jobs per partition at the same time.
- You can wrap
ConcurrentPartitioner
into anotherLimitedParallelExecutor
to enforce a global degree of parallelism across all partitions. ConcurrentPartitioner
is designed to automatically clean up its internal storage for unused partitions, so you don't have to worry about memory leaks if you generate a huge number of different partition keys over a long period of time.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
-
.NETStandard 2.1
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
3.0.0 | 10,553 | 9/14/2023 |
3.0.0-rc1 | 102 | 9/13/2023 |
2.1.0 | 5,276 | 12/16/2022 |
2.0.0 | 2,254 | 8/26/2022 |
1.1.0 | 1,121 | 8/4/2021 |
1.1.0-rc1 | 242 | 8/4/2021 |
1.0.2 | 324 | 8/4/2021 |
1.0.1 | 410 | 7/28/2021 |
1.0.0 | 635 | 6/24/2021 |
1.0.0-rc4 | 216 | 6/23/2021 |
1.0.0-rc3 | 284 | 6/23/2021 |
1.0.0-rc2 | 193 | 6/22/2021 |
1.0.0-rc1 | 232 | 6/22/2021 |