AsyncKeyedLock 7.0.0-rc3

AsyncKeyedLock AsyncKeyedLock

GitHub Workflow Status NuGet NuGet Codacy Grade Codecov

An asynchronous .NET Standard 2.0 library that allows you to lock based on a key (keyed semaphores), limiting concurrent threads sharing the same key to a specified number, with optional pooling for reducing memory allocations.

For example, suppose you were processing financial transactions, but while working on one account you wouldn't want to concurrently process a transaction for the same account. Of course, you could just add a normal lock, but then you can only process one transaction at a time. If you're processing a transaction for account A, you may want to also be processing a separate transaction for account B. That's where AsyncKeyedLock comes in: it allows you to lock but only if the key matches.

The library uses two very different methods for locking, AsyncKeyedLocker which uses an underlying ConcurrentDictionary that's cleaned up after use and StripedAsyncKeyedLocker which uses a technique called striped locking. Both have their advantages and disadvantages, and in order to help you choose you are highly recommended to read about it in the wiki.

A simple non-keyed lock is also available through AsyncNonKeyedLocker.

Installation and usage

Using this library is straightforward. Here's a simple example for using AsyncKeyedLocker:

private static readonly AsyncKeyedLocker<string> _asyncKeyedLocker = new(o =>
  {
    o.PoolSize = 20; // this is NOT a concurrency limit
    o.PoolInitialFill = 1;
  });

...

using (await _asyncKeyedLocker.LockAsync("test123"))
{
  ...
}

This libary also supports conditional locking, whether for AsyncKeyedLocker, StripedAsyncKeyedLocker or AsyncNonKeyedLocker. This could provide a workaround for reentrancy in some scenarios for example in recursion:

double factorial = Factorial(number);

public static double Factorial(int number, bool isFirst = true)
{
  using (await _asyncKeyedLocker.ConditionalLockAsync("test123", isFirst))
  {
    if (number == 0)
      return 1;
    return number * Factorial(number-1, false);
  }
}

For more help with AsyncKeyedLocker or for examples with StripedAsyncKeyedLocker or AsyncNonKeyedLocker (for simple, non-keyed locking), please take a look at our wiki.

Benchmarks

This library has been extensively benchmarked against several other options and our benchmarks run publicly and transparently on Github Actions.

Credits

Check out our list of contributors!

Showing the top 20 packages that depend on AsyncKeyedLock.

Packages Downloads
Volo.Abp.DistributedLocking.Abstractions
Package Description
37
Volo.Abp.DistributedLocking.Abstractions
Package Description
34
Volo.Abp.DistributedLocking.Abstractions
Package Description
33
Volo.Abp.DistributedLocking.Abstractions
Package Description
32
Volo.Abp.DistributedLocking.Abstractions
Package Description
31

Support for .NET 9.0's System.Threading.Lock.

.NET 5.0

  • No dependencies.

.NET 8.0

  • No dependencies.

.NET 9.0

  • No dependencies.

.NET Standard 2.0

.NET Standard 2.1

  • No dependencies.

Version Downloads Last updated
7.1.8 5 11/25/2025
7.1.8-beta5 5 11/25/2025
7.1.8-beta4 4 11/25/2025
7.1.8-beta3 4 11/25/2025
7.1.8-beta2 6 11/25/2025
7.1.8-beta 4 11/25/2025
7.1.7 7 10/10/2025
7.1.6 36 4/16/2025
7.1.5-alpha 31 4/16/2025
7.1.4 35 3/15/2025
7.1.4-preview 30 3/15/2025
7.1.3 35 3/15/2025
7.0.2 35 3/15/2025
7.0.1 34 3/15/2025
7.0.0 35 3/15/2025
7.0.0-rc3 33 3/15/2025
7.0.0-rc2 32 3/15/2025
7.0.0-rc1 36 3/15/2025
7.0.0-beta 35 3/15/2025
7.0.0-alpha 35 3/15/2025
6.4.2 34 3/15/2025
6.4.1 37 3/15/2025
6.4.0 36 3/15/2025
6.3.4 39 3/15/2025
6.3.4-rc 32 3/15/2025
6.3.4-beta 32 3/15/2025
6.3.3 33 3/15/2025
6.3.2 36 3/15/2025
6.3.0 40 3/15/2025
6.2.6 32 3/15/2025
6.2.5 37 3/15/2025
6.2.4 36 3/15/2025
6.2.3 35 3/15/2025
6.2.3-beta 38 3/15/2025
6.2.2 39 3/15/2025
6.2.1 37 3/15/2025
6.2.0 38 3/15/2025
6.1.1 32 3/15/2025
6.1.1-rc 33 3/15/2025
6.1.1-beta 40 3/15/2025
6.1.0 38 3/15/2025
6.0.5 40 3/15/2025
6.0.5-alpha 33 3/15/2025
6.0.4 35 3/15/2025
6.0.4-rc6 34 3/15/2025
6.0.4-rc5 31 3/15/2025
6.0.4-rc3 28 3/15/2025
6.0.4-rc 41 3/15/2025
6.0.4-beta 33 3/15/2025
6.0.4-alpha 26 3/15/2025
6.0.3 34 3/15/2025
6.0.2 36 3/15/2025
6.0.1 44 3/15/2025
5.1.2 39 3/15/2025
5.1.1 36 3/15/2025
5.1.0 34 3/15/2025
5.0.4 34 3/15/2025
5.0.3 35 3/15/2025
5.0.3-rc 40 3/15/2025
5.0.2-rc 40 3/15/2025
5.0.1 36 3/15/2025
4.0.2 41 3/15/2025
3.2.3 39 3/15/2025
3.2.1 38 3/15/2025
3.2.0 38 3/15/2025
3.0.1 35 3/15/2025
3.0.0 36 3/15/2025
2.0.3 36 3/15/2025
2.0.2 40 3/15/2025
2.0.1 34 3/15/2025
2.0.0 33 3/15/2025
1.1.0 38 3/15/2025
1.0.1 37 3/15/2025
1.0.0 41 3/15/2025