LimitedConcurrency 3.0.0

dotnet add package LimitedConcurrency --version 3.0.0                
NuGet\Install-Package LimitedConcurrency -Version 3.0.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="LimitedConcurrency" Version="3.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add LimitedConcurrency --version 3.0.0                
#r "nuget: LimitedConcurrency, 3.0.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// 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 Tasks 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 passed Func<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 of ExecuteAsync
  • 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 another LimitedParallelExecutor 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .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,506 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