Skip to content

Commit

Permalink
Performance improvement on AsyncNonKeyedLocker.
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkCiliaVincenti committed Jan 14, 2024
1 parent 9c9f09d commit 889a0c0
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 50 deletions.
8 changes: 4 additions & 4 deletions AsyncKeyedLock/AsyncKeyedLock.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
<PackageProjectUrl>https://github.com/MarkCiliaVincenti/AsyncKeyedLock</PackageProjectUrl>
<Copyright>MIT</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Version>6.3.0</Version>
<Version>6.3.1</Version>
<PackageIcon>logo.png</PackageIcon>
<PackageReleaseNotes>Added a simple, non-keyed async lock through AsyncNonKeyedLocker.</PackageReleaseNotes>
<PackageReleaseNotes>Performance improvement on AsyncNonKeyedLocker.</PackageReleaseNotes>
<Description>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.</Description>
<Copyright>© 2024 Mark Cilia Vincenti</Copyright>
<PackageTags>async,lock,key,keyed,semaphore,striped,dictionary,concurrentdictionary,pooling,duplicate,synchronization</PackageTags>
<RepositoryType>git</RepositoryType>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<AssemblyVersion>6.3.0.0</AssemblyVersion>
<FileVersion>6.3.0.0</FileVersion>
<AssemblyVersion>6.3.1.0</AssemblyVersion>
<FileVersion>6.3.1.0</FileVersion>
<PackageReadmeFile>README.md</PackageReadmeFile>
<IsPackable>true</IsPackable>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
Expand Down
13 changes: 4 additions & 9 deletions AsyncKeyedLock/AsyncNonKeyedLockReleaser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,11 @@ namespace AsyncKeyedLock
/// </summary>
public readonly struct AsyncNonKeyedLockReleaser : IDisposable
{
private readonly SemaphoreSlim _semaphoreSlim;
private readonly AsyncNonKeyedLocker _locker;

/// <summary>
/// The exposed <see cref="SemaphoreSlim"/> instance used to limit the number of threads that can access the lock concurrently.
/// </summary>
public readonly SemaphoreSlim SemaphoreSlim => _semaphoreSlim;

internal AsyncNonKeyedLockReleaser(SemaphoreSlim semaphoreSlim)
internal AsyncNonKeyedLockReleaser(AsyncNonKeyedLocker locker)
{
_semaphoreSlim = semaphoreSlim;
_locker = locker;
}

/// <summary>
Expand All @@ -27,7 +22,7 @@ internal AsyncNonKeyedLockReleaser(SemaphoreSlim semaphoreSlim)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly void Dispose()
{
_semaphoreSlim.Release();
_locker._semaphoreSlim.Release();
}
}
}
18 changes: 4 additions & 14 deletions AsyncKeyedLock/AsyncNonKeyedLockTimeoutReleaser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,12 @@ namespace AsyncKeyedLock
{
private readonly bool _enteredSemaphore;

/// <summary>
/// True if the timeout was reached, false if not.
/// </summary>
public readonly bool EnteredSemaphore => _enteredSemaphore;

private readonly SemaphoreSlim _semaphoreSlim;

/// <summary>
/// The exposed <see cref="SemaphoreSlim"/> instance used to limit the number of threads that can access the lock concurrently.
/// </summary>
public readonly SemaphoreSlim SemaphoreSlim => _semaphoreSlim;
private readonly AsyncNonKeyedLocker _locker;

internal AsyncNonKeyedLockTimeoutReleaser(SemaphoreSlim semaphoreSlim, bool enteredSemaphore)
internal AsyncNonKeyedLockTimeoutReleaser(AsyncNonKeyedLocker locker, bool enteredSemaphore)
{
_locker = locker;
_enteredSemaphore = enteredSemaphore;
_semaphoreSlim = semaphoreSlim;
}

/// <summary>
Expand All @@ -37,7 +27,7 @@ public readonly void Dispose()
{
if (_enteredSemaphore)
{
_semaphoreSlim.Release();
_locker._semaphoreSlim.Release();
}
}
}
Expand Down
46 changes: 23 additions & 23 deletions AsyncKeyedLock/AsyncNonKeyedLocker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public sealed class AsyncNonKeyedLocker : IDisposable
/// </summary>
public int MaxCount => _maxCount;

private SemaphoreSlim _semaphoreSlim;
internal SemaphoreSlim _semaphoreSlim;

/// <summary>
/// The maximum number of requests for the semaphore that can be granted concurrently. Defaults to 1.
Expand All @@ -37,7 +37,7 @@ public AsyncNonKeyedLocker(int maxCount = 1)
public IDisposable Lock()
{
_semaphoreSlim.Wait();
return new AsyncNonKeyedLockReleaser(_semaphoreSlim);
return new AsyncNonKeyedLockReleaser(this);
}

/// <summary>
Expand All @@ -49,7 +49,7 @@ public IDisposable Lock()
public IDisposable Lock(CancellationToken cancellationToken)
{
_semaphoreSlim.Wait(cancellationToken);
return new AsyncNonKeyedLockReleaser(_semaphoreSlim);
return new AsyncNonKeyedLockReleaser(this);
}

/// <summary>
Expand All @@ -62,7 +62,7 @@ public IDisposable Lock(CancellationToken cancellationToken)
public AsyncNonKeyedLockTimeoutReleaser Lock(int millisecondsTimeout, out bool entered)
{
entered = _semaphoreSlim.Wait(millisecondsTimeout);
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}

/// <summary>
Expand All @@ -75,7 +75,7 @@ public AsyncNonKeyedLockTimeoutReleaser Lock(int millisecondsTimeout, out bool e
public AsyncNonKeyedLockTimeoutReleaser Lock(TimeSpan timeout, out bool entered)
{
entered = _semaphoreSlim.Wait(timeout);
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}

/// <summary>
Expand All @@ -97,7 +97,7 @@ public AsyncNonKeyedLockTimeoutReleaser Lock(int millisecondsTimeout, Cancellati
entered = false;
throw;
}
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}

/// <summary>
Expand All @@ -119,7 +119,7 @@ public AsyncNonKeyedLockTimeoutReleaser Lock(TimeSpan timeout, CancellationToken
entered = false;
throw;
}
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}
#endregion Synchronous

Expand All @@ -133,7 +133,7 @@ public AsyncNonKeyedLockTimeoutReleaser Lock(TimeSpan timeout, CancellationToken
public async ValueTask<IDisposable> LockAsync(bool continueOnCapturedContext = false)
{
await _semaphoreSlim.WaitAsync().ConfigureAwait(continueOnCapturedContext);
return new AsyncNonKeyedLockReleaser(_semaphoreSlim);
return new AsyncNonKeyedLockReleaser(this);
}

/// <summary>
Expand All @@ -146,7 +146,7 @@ public async ValueTask<IDisposable> LockAsync(bool continueOnCapturedContext = f
public async ValueTask<IDisposable> LockAsync(CancellationToken cancellationToken, bool continueOnCapturedContext = false)
{
await _semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext);
return new AsyncNonKeyedLockReleaser(_semaphoreSlim);
return new AsyncNonKeyedLockReleaser(this);
}

/// <summary>
Expand All @@ -159,7 +159,7 @@ public async ValueTask<IDisposable> LockAsync(CancellationToken cancellationToke
public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(int millisecondsTimeout, bool continueOnCapturedContext = false)
{
bool entered = await _semaphoreSlim.WaitAsync(millisecondsTimeout).ConfigureAwait(continueOnCapturedContext);
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}

/// <summary>
Expand All @@ -172,7 +172,7 @@ public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(int milliseco
public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(TimeSpan timeout, bool continueOnCapturedContext = false)
{
bool entered = await _semaphoreSlim.WaitAsync(timeout).ConfigureAwait(continueOnCapturedContext);
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}

/// <summary>
Expand All @@ -188,11 +188,11 @@ public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(int milliseco
try
{
bool entered = await _semaphoreSlim.WaitAsync(millisecondsTimeout, cancellationToken).ConfigureAwait(continueOnCapturedContext);
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}
catch (OperationCanceledException)
{
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, false);
return new AsyncNonKeyedLockTimeoutReleaser(this, false);
throw;
}
}
Expand All @@ -210,11 +210,11 @@ public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(TimeSpan time
try
{
bool entered = await _semaphoreSlim.WaitAsync(timeout, cancellationToken).ConfigureAwait(continueOnCapturedContext);
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}
catch (OperationCanceledException)
{
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, false);
return new AsyncNonKeyedLockTimeoutReleaser(this, false);
throw;
}
}
Expand All @@ -231,7 +231,7 @@ public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(TimeSpan time
public async ValueTask<IDisposable> LockAsync(ConfigureAwaitOptions configureAwaitOptions)
{
await _semaphoreSlim.WaitAsync().ConfigureAwait(configureAwaitOptions);
return new AsyncNonKeyedLockReleaser(_semaphoreSlim);
return new AsyncNonKeyedLockReleaser(this);
}

/// <summary>
Expand All @@ -244,7 +244,7 @@ public async ValueTask<IDisposable> LockAsync(ConfigureAwaitOptions configureAwa
public async ValueTask<IDisposable> LockAsync(CancellationToken cancellationToken, ConfigureAwaitOptions configureAwaitOptions)
{
await _semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(configureAwaitOptions);
return new AsyncNonKeyedLockReleaser(_semaphoreSlim);
return new AsyncNonKeyedLockReleaser(this);
}

/// <summary>
Expand All @@ -257,7 +257,7 @@ public async ValueTask<IDisposable> LockAsync(CancellationToken cancellationToke
public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(int millisecondsTimeout, ConfigureAwaitOptions configureAwaitOptions)
{
bool entered = await _semaphoreSlim.WaitAsync(millisecondsTimeout).ConfigureAwait(configureAwaitOptions);
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}

/// <summary>
Expand All @@ -270,7 +270,7 @@ public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(int milliseco
public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(TimeSpan timeout, ConfigureAwaitOptions configureAwaitOptions)
{
bool entered = await _semaphoreSlim.WaitAsync(timeout).ConfigureAwait(configureAwaitOptions);
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}

/// <summary>
Expand All @@ -286,11 +286,11 @@ public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(int milliseco
try
{
bool entered = await _semaphoreSlim.WaitAsync(millisecondsTimeout, cancellationToken).ConfigureAwait(configureAwaitOptions);
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}
catch (OperationCanceledException)
{
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, false);
return new AsyncNonKeyedLockTimeoutReleaser(this, false);
throw;
}
}
Expand All @@ -308,11 +308,11 @@ public async ValueTask<AsyncNonKeyedLockTimeoutReleaser> LockAsync(TimeSpan time
try
{
bool entered = await _semaphoreSlim.WaitAsync(timeout, cancellationToken).ConfigureAwait(configureAwaitOptions);
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, entered);
return new AsyncNonKeyedLockTimeoutReleaser(this, entered);
}
catch (OperationCanceledException)
{
return new AsyncNonKeyedLockTimeoutReleaser(_semaphoreSlim, false);
return new AsyncNonKeyedLockTimeoutReleaser(this, false);
throw;
}
}
Expand Down

0 comments on commit 889a0c0

Please sign in to comment.