{"id":36924119,"url":"https://github.com/MarkCiliaVincenti/AsyncKeyedLock","last_synced_at":"2026-01-19T18:00:41.897Z","repository":{"id":52446316,"uuid":"430633055","full_name":"MarkCiliaVincenti/AsyncKeyedLock","owner":"MarkCiliaVincenti","description":"An asynchronous .NET 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.","archived":false,"fork":false,"pushed_at":"2026-01-02T15:54:25.000Z","size":464,"stargazers_count":299,"open_issues_count":0,"forks_count":17,"subscribers_count":8,"default_branch":"master","last_synced_at":"2026-01-14T08:53:09.646Z","etag":null,"topics":["async","duplicate","key","keyed","lock","pooling","semaphore","semaphores","semaphoreslim","synchronization"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/AsyncKeyedLock","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MarkCiliaVincenti.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["MarkCiliaVincenti"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2021-11-22T09:00:26.000Z","updated_at":"2026-01-06T14:18:55.000Z","dependencies_parsed_at":"2023-12-21T12:41:36.864Z","dependency_job_id":"25547223-637c-4a6f-b5ec-fa5e949fdaf4","html_url":"https://github.com/MarkCiliaVincenti/AsyncKeyedLock","commit_stats":{"total_commits":106,"total_committers":5,"mean_commits":21.2,"dds":0.05660377358490565,"last_synced_commit":"b8ccd92aff81c3561412327178e5224dfa71c669"},"previous_names":[],"tags_count":55,"template":false,"template_full_name":null,"purl":"pkg:github/MarkCiliaVincenti/AsyncKeyedLock","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkCiliaVincenti%2FAsyncKeyedLock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkCiliaVincenti%2FAsyncKeyedLock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkCiliaVincenti%2FAsyncKeyedLock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkCiliaVincenti%2FAsyncKeyedLock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MarkCiliaVincenti","download_url":"https://codeload.github.com/MarkCiliaVincenti/AsyncKeyedLock/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkCiliaVincenti%2FAsyncKeyedLock/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28578952,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T17:42:58.221Z","status":"ssl_error","status_checked_at":"2026-01-19T17:40:54.158Z","response_time":67,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","duplicate","key","keyed","lock","pooling","semaphore","semaphores","semaphoreslim","synchronization"],"created_at":"2026-01-12T19:00:25.486Z","updated_at":"2026-01-19T18:00:41.891Z","avatar_url":"https://github.com/MarkCiliaVincenti.png","language":"C#","funding_links":["https://github.com/sponsors/MarkCiliaVincenti"],"categories":["C# #"],"sub_categories":[],"readme":"# ![AsyncKeyedLock](https://raw.githubusercontent.com/MarkCiliaVincenti/AsyncKeyedLock/master/logo32.png)\u0026nbsp;AsyncKeyedLock\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/MarkCiliaVincenti/AsyncKeyedLock/dotnet.yml?branch=master\u0026logo=github\u0026style=flat)](https://actions-badge.atrox.dev/MarkCiliaVincenti/AsyncKeyedLock/goto?ref=master) [![NuGet](https://img.shields.io/nuget/v/AsyncKeyedLock?label=NuGet\u0026logo=nuget\u0026style=flat)](https://www.nuget.org/packages/AsyncKeyedLock) [![NuGet](https://img.shields.io/nuget/dt/AsyncKeyedLock?logo=nuget\u0026style=flat)](https://www.nuget.org/packages/AsyncKeyedLock) [![Codacy Grade](https://img.shields.io/codacy/grade/315c3d5a06a441bda26ffd88e705fa63?style=flat)](https://app.codacy.com/gh/MarkCiliaVincenti/AsyncKeyedLock/dashboard) [![Codecov](https://img.shields.io/codecov/c/github/MarkCiliaVincenti/AsyncKeyedLock?label=coverage\u0026logo=codecov\u0026style=flat)](https://app.codecov.io/gh/MarkCiliaVincenti/AsyncKeyedLock)\n\nAn asynchronous .NET 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.\n\nFor 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.\n\nThe 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](https://github.com/MarkCiliaVincenti/AsyncKeyedLock/wiki).\n\nA simple non-keyed lock is also available through [`AsyncNonKeyedLocker`](https://github.com/MarkCiliaVincenti/AsyncKeyedLock/wiki/How-to-use-AsyncNonKeyedLocker).\n\n## Installation and usage\nUsing this library is straightforward. Here's a simple example for using `AsyncKeyedLocker`:\n```csharp\nprivate static readonly AsyncKeyedLocker\u003cstring\u003e _asyncKeyedLocker = new();\n\n...\n\nusing (await _asyncKeyedLocker.LockAsync(\"test123\"))\n{\n  ...\n}\n```\n\nor with timeouts:\n```csharp\nprivate static readonly AsyncKeyedLocker\u003cstring\u003e _asyncKeyedLocker = new();\nprivate const _timeout = 100;\n\n...\n\nusing (var releaser = await _asyncKeyedLocker.LockOrNullAsync(\"test123\", _timeout))\n{\n  if (releaser is not null)\n  {\n    ...\n  }\n}\n```\n\nThis 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:\n```csharp\ndouble factorial = Factorial(number);\n\npublic static double Factorial(int number, bool isFirst = true)\n{\n  using (await _asyncKeyedLocker.ConditionalLockAsync(\"test123\", isFirst))\n  {\n    if (number == 0)\n      return 1;\n    return number * Factorial(number-1, false);\n  }\n}\n```\n\nFor more help with `AsyncKeyedLocker`, or for examples with `StripedAsyncKeyedLocker` or `AsyncNonKeyedLocker` (for simple, non-keyed locking), please [take a look at our wiki](https://github.com/MarkCiliaVincenti/AsyncKeyedLock/wiki).\n\n## Pooling change in v7.0.0\nPrior to AsyncKeyedLock 7.0.0, pooling was disabled by default and you needed to specify a pool size in order to enable it. Since v7.0.0, pooling is enabled by default with an initial fill of 1 and a pool size of 20. In order to disable pooling (not recommended), you need to now specify a pool size of 0 within AsyncKeyedLockOptions. Read more about pooling in [our wiki](https://github.com/MarkCiliaVincenti/AsyncKeyedLock/wiki/How-to-use-AsyncKeyedLocker#pooling).\n\n## Non-generic constructor removal in v8.0.0\nAs of v8.0.0, the non-generic constructors for `AsyncKeyedLocker` have been removed. These were already marked as obsolete; if you were using them, please switch to `AsyncKeyedLocker\u003cobject\u003e`.\n\n## Benchmarks\nThis library has been extensively benchmarked against several other options and [our benchmarks](https://github.com/MarkCiliaVincenti/AsyncKeyedLock/wiki/Benchmarks) run publicly and transparently on Github Actions.\n\n## Credits\nCheck out our [list of contributors](https://github.com/MarkCiliaVincenti/AsyncKeyedLock/blob/master/CONTRIBUTORS.md)!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMarkCiliaVincenti%2FAsyncKeyedLock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMarkCiliaVincenti%2FAsyncKeyedLock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMarkCiliaVincenti%2FAsyncKeyedLock/lists"}