From c23365bbf83bfa1b015f3a482c49c4703a4da5cd Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Mon, 9 Oct 2023 09:08:22 +0200 Subject: [PATCH] =?UTF-8?q?6.2.2=20=E2=80=94=20Fixed=20potential=20unneces?= =?UTF-8?q?sary=20slowdown.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AsyncKeyedLock.Tests.csproj | 8 ++--- .../StripedAsyncKeyedLocker/OriginalTests.cs | 5 ++-- .../TestsForStripedAsyncKeyedLock.cs | 12 ++++---- ...TestsForStripedAsyncKeyedLockDictionary.cs | 30 +++++++++---------- AsyncKeyedLock/AsyncKeyedLock.csproj | 8 ++--- AsyncKeyedLock/AsyncKeyedLockDictionary.cs | 2 +- 6 files changed, 32 insertions(+), 33 deletions(-) diff --git a/AsyncKeyedLock.Tests/AsyncKeyedLock.Tests.csproj b/AsyncKeyedLock.Tests/AsyncKeyedLock.Tests.csproj index f4d1486..e5e7316 100644 --- a/AsyncKeyedLock.Tests/AsyncKeyedLock.Tests.csproj +++ b/AsyncKeyedLock.Tests/AsyncKeyedLock.Tests.csproj @@ -9,11 +9,11 @@ - + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/OriginalTests.cs b/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/OriginalTests.cs index 09daf5b..5ae30d1 100644 --- a/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/OriginalTests.cs +++ b/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/OriginalTests.cs @@ -1,6 +1,5 @@ using ListShuffle; using System.Collections.Concurrent; -using System.Threading.Tasks; using Xunit; namespace AsyncKeyedLock.Tests.StripedAsyncKeyedLocker @@ -180,7 +179,7 @@ public async Task BenchmarkSimulationTest() { var key = i % NumberOfLocks; - using (var myLock = await AsyncKeyedLocker.LockAsync(key.ToString()).ConfigureAwait(false)) + using (var myLock = await AsyncKeyedLocker.LockAsync(key.ToString())) { for (int j = 0; j < GuidReversals; j++) { @@ -199,7 +198,7 @@ public async Task BenchmarkSimulationTest() await Task.Yield(); }).AsParallel(); - await Task.WhenAll(AsyncKeyedLockerTasks).ConfigureAwait(false); + await Task.WhenAll(AsyncKeyedLockerTasks); } } diff --git a/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/TestsForStripedAsyncKeyedLock.cs b/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/TestsForStripedAsyncKeyedLock.cs index 5e32733..b99e5a6 100644 --- a/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/TestsForStripedAsyncKeyedLock.cs +++ b/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/TestsForStripedAsyncKeyedLock.cs @@ -23,11 +23,11 @@ public async Task ShouldRunThreadsWithDistinctKeysInParallel() // 100 threads, 100 keys var threads = Enumerable.Range(0, 100) - .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i).ConfigureAwait(false))) + .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i))) .ToList(); // Act - await Task.WhenAll(threads).ConfigureAwait(false); + await Task.WhenAll(threads); maxParallelism.Should().BeGreaterThan(10); @@ -44,7 +44,7 @@ async Task OccupyTheLockALittleBit(int key) const int delay = 250; - await Task.Delay(TimeSpan.FromMilliseconds(delay)).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromMilliseconds(delay)); Interlocked.Decrement(ref currentParallelism); } @@ -62,11 +62,11 @@ public async Task ShouldRunThreadsWithSameKeysLinearly() // 100 threads, 10 keys var threads = Enumerable.Range(0, 100) - .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i % 10).ConfigureAwait(false))) + .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i % 10))) .ToList(); // Act + Assert - await Task.WhenAll(threads).ConfigureAwait(false); + await Task.WhenAll(threads); maxParallelism.Should().BeLessOrEqualTo(10); @@ -93,7 +93,7 @@ async Task OccupyTheLockALittleBit(int key) const int delay = 10; - await Task.Delay(TimeSpan.FromMilliseconds(delay)).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromMilliseconds(delay)); if (!runningTasksIndex.TryRemove(key, out var value)) { diff --git a/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/TestsForStripedAsyncKeyedLockDictionary.cs b/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/TestsForStripedAsyncKeyedLockDictionary.cs index 93894b9..00499d3 100644 --- a/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/TestsForStripedAsyncKeyedLockDictionary.cs +++ b/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/TestsForStripedAsyncKeyedLockDictionary.cs @@ -20,11 +20,11 @@ public async Task ShouldRunThreadsWithDistinctKeysInParallel() // 100 threads, 100 keys var threads = Enumerable.Range(0, 100) - .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i).ConfigureAwait(false))) + .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i))) .ToList(); // Act - await Task.WhenAll(threads).ConfigureAwait(false); + await Task.WhenAll(threads); maxParallelism.Should().BeGreaterThan(10); foreach (var key in Enumerable.Range(0, 100)) @@ -46,7 +46,7 @@ async Task OccupyTheLockALittleBit(int key) const int delay = 250; - await Task.Delay(TimeSpan.FromMilliseconds(delay)).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromMilliseconds(delay)); Interlocked.Decrement(ref currentParallelism); } @@ -65,11 +65,11 @@ public async Task ShouldRunThreadsWithSameKeysLinearly() // 100 threads, 10 keys var threads = Enumerable.Range(0, 100) - .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i % 10).ConfigureAwait(false))) + .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i % 10))) .ToList(); // Act + Assert - await Task.WhenAll(threads).ConfigureAwait(false); + await Task.WhenAll(threads); maxParallelism.Should().BeLessOrEqualTo(10); foreach (var key in Enumerable.Range(0, 100)) @@ -99,7 +99,7 @@ async Task OccupyTheLockALittleBit(int key) const int delay = 10; - await Task.Delay(TimeSpan.FromMilliseconds(delay)).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromMilliseconds(delay)); if (!runningTasksIndex.TryRemove(key, out var value)) { @@ -135,11 +135,11 @@ public async Task ShouldNeverCreateTwoSemaphoresForTheSameKey() // Many threads, 1 key var threads = Enumerable.Range(0, 100) - .Select(_ => Task.Run(async () => await OccupyTheLockALittleBit(1).ConfigureAwait(false))) + .Select(_ => Task.Run(async () => await OccupyTheLockALittleBit(1))) .ToList(); // Act + Assert - await Task.WhenAll(threads).ConfigureAwait(false); + await Task.WhenAll(threads); maxParallelism.Should().Be(1); stripedAyncKeyedLocks.IsInUse(1).Should().BeFalse(); @@ -150,7 +150,7 @@ async Task OccupyTheLockALittleBit(int key) var currentTaskId = Task.CurrentId ?? -1; var delay = random.Next(500); - await Task.Delay(delay).ConfigureAwait(false); + await Task.Delay(delay); using (await stripedAyncKeyedLocks.LockAsync(key)) { @@ -201,11 +201,11 @@ public async Task ShouldRunThreadsWithDistinctStringKeysInParallel() // 100 threads, 100 keys var threads = Enumerable.Range(0, 100) - .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i).ConfigureAwait(false))) + .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i))) .ToList(); // Act - await Task.WhenAll(threads).ConfigureAwait(false); + await Task.WhenAll(threads); maxParallelism.Should().BeGreaterThan(10); foreach (var key in Enumerable.Range(0, 100)) @@ -226,7 +226,7 @@ async Task OccupyTheLockALittleBit(int key) const int delay = 250; - await Task.Delay(TimeSpan.FromMilliseconds(delay)).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromMilliseconds(delay)); Interlocked.Decrement(ref currentParallelism); } @@ -241,11 +241,11 @@ public async Task IsInUseShouldReturnTrueWhenLockedAndFalseWhenNotLocked() // 10 threads, 10 keys var threads = Enumerable.Range(0, 10) - .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i).ConfigureAwait(false))) + .Select(i => Task.Run(async () => await OccupyTheLockALittleBit(i))) .ToList(); // Act - await Task.WhenAll(threads).ConfigureAwait(false); + await Task.WhenAll(threads); foreach (var key in Enumerable.Range(0, 10)) { stripedAyncKeyedLocks.IsInUse(key).Should().BeFalse(); @@ -259,7 +259,7 @@ async Task OccupyTheLockALittleBit(int key) { const int delay = 250; - await Task.Delay(TimeSpan.FromMilliseconds(delay)).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromMilliseconds(delay)); stripedAyncKeyedLocks.IsInUse(key).Should().BeTrue(); } diff --git a/AsyncKeyedLock/AsyncKeyedLock.csproj b/AsyncKeyedLock/AsyncKeyedLock.csproj index a781f2a..b09114b 100644 --- a/AsyncKeyedLock/AsyncKeyedLock.csproj +++ b/AsyncKeyedLock/AsyncKeyedLock.csproj @@ -8,16 +8,16 @@ https://github.com/MarkCiliaVincenti/AsyncKeyedLock MIT MIT - 6.2.1 + 6.2.2 logo.png - Implemented IDisposable. + Fixed potential unnecessary slowdown. 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. © 2023 Mark Cilia Vincenti async,lock,key,keyed,semaphore,striped,dictionary,concurrentdictionary,pooling,duplicate,synchronization git false - 6.2.1.0 - 6.2.1.0 + 6.2.2.0 + 6.2.2.0 README.md true true diff --git a/AsyncKeyedLock/AsyncKeyedLockDictionary.cs b/AsyncKeyedLock/AsyncKeyedLockDictionary.cs index e7d3a07..7b71095 100644 --- a/AsyncKeyedLock/AsyncKeyedLockDictionary.cs +++ b/AsyncKeyedLock/AsyncKeyedLockDictionary.cs @@ -103,7 +103,7 @@ public AsyncKeyedLockReleaser GetOrAdd(TKey key) } if (releaser.TryIncrement(key)) { - releaser.IsNotInUse = true; + releaserToAdd.IsNotInUse = true; _pool.PutObject(releaserToAdd); return releaser; }