From b1f4df088aa22f030b65471baf6f2006477f9e66 Mon Sep 17 00:00:00 2001 From: electricessence <5899455+electricessence@users.noreply.github.com> Date: Tue, 25 Jun 2024 21:32:51 -0700 Subject: [PATCH] Optimize async operations with `default` - Replaced `new ValueTask()` with `default` across async operations for better performance. - In `BasicTests.cs`, updated `ReadAllAsync` method calls for efficiency. - `SourceTests.cs` now uses `Assert.ThrowsAsync` for testing task cancellations. - In `Extensions.Read.cs`, renamed `index` to `count` and simplified async read logic. - Removed unnecessary cancellation checks in some async operations. - Applied `ValueTask` optimization in write extensions for consistency. - Updated project version to 8.4.1, indicating minor improvements and optimizations. --- Open.ChannelExtensions.Tests/BasicTests.cs | 6 ++--- Open.ChannelExtensions.Tests/SourceTests.cs | 5 ++-- Open.ChannelExtensions/Extensions.Read.cs | 24 +++++++++---------- .../Extensions.ReadConcurrently.cs | 4 ++-- Open.ChannelExtensions/Extensions.Write.cs | 4 ++-- .../Extensions.WriteConcurrently.cs | 4 ++-- Open.ChannelExtensions/Extensions._.cs | 4 ++-- .../Open.ChannelExtensions.csproj | 2 +- 8 files changed, 26 insertions(+), 27 deletions(-) diff --git a/Open.ChannelExtensions.Tests/BasicTests.cs b/Open.ChannelExtensions.Tests/BasicTests.cs index b642fc1..22c7a56 100644 --- a/Open.ChannelExtensions.Tests/BasicTests.cs +++ b/Open.ChannelExtensions.Tests/BasicTests.cs @@ -187,7 +187,7 @@ public static async Task ReadAllAsync(int testSize) .ReadAllAsync(i => { result.Add(i); - return new ValueTask(); + return default; }); sw.Stop(); @@ -221,7 +221,7 @@ public static async Task PipeToBounded(int testSize) .ReadAllAsync(i => { result.Add(i); - return new ValueTask(); + return default; }); sw.Stop(); @@ -255,7 +255,7 @@ public static async Task PipeToUnbound(int testSize) .ReadAllAsync(i => { result.Add(i); - return new ValueTask(); + return default; }); sw.Stop(); diff --git a/Open.ChannelExtensions.Tests/SourceTests.cs b/Open.ChannelExtensions.Tests/SourceTests.cs index 7f14e73..e9009ef 100644 --- a/Open.ChannelExtensions.Tests/SourceTests.cs +++ b/Open.ChannelExtensions.Tests/SourceTests.cs @@ -15,7 +15,7 @@ public static async Task ToChannelCancelledAfterwriteStarts() catch (OperationCanceledException) { } - await reader.ReadAll(_ => { }); + await Assert.ThrowsAsync(() => reader.ReadAll(_ => { }).AsTask()); await Assert.ThrowsAsync(() => reader.Completion); } @@ -26,8 +26,7 @@ public static async Task ToChannelCancelledBeforeWriteStarts() cts.Cancel(); var reader = Enumerable.Range(0, 10_000).ToChannel(10, true, cts.Token); - var count = await reader.ReadAll(_ => { }); - Assert.Equal(0, count); + await Assert.ThrowsAsync(() => reader.ReadAll(_ => { }).AsTask()); await Assert.ThrowsAsync(() => reader.Completion); } } diff --git a/Open.ChannelExtensions/Extensions.Read.cs b/Open.ChannelExtensions/Extensions.Read.cs index 802d359..7bece0a 100644 --- a/Open.ChannelExtensions/Extensions.Read.cs +++ b/Open.ChannelExtensions/Extensions.Read.cs @@ -102,7 +102,6 @@ public static async ValueTask> ReadBatchAsync(this ChannelReader r if (results.Count == max) return results; - cancellationToken.ThrowIfCancellationRequested(); } while (await reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false)); } @@ -134,8 +133,9 @@ public static async ValueTask ReadUntilCancelledAsync(this ChannelReade if (deferredExecution) await Task.Yield(); - long index = 0; + long count = 0; + // Note: if the channel has complete with an OperationCanceledException, this will throw when waiting to read. if (cancellationToken.CanBeCanceled) { do @@ -144,7 +144,7 @@ public static async ValueTask ReadUntilCancelledAsync(this ChannelReade !cancellationToken.IsCancellationRequested && reader.TryRead(out T? item)) { - await receiver(item, index++).ConfigureAwait(false); + await receiver(item, count++).ConfigureAwait(false); } } while ( @@ -157,13 +157,13 @@ public static async ValueTask ReadUntilCancelledAsync(this ChannelReade { while (reader.TryRead(out T? item)) { - await receiver(item, index++).ConfigureAwait(false); + await receiver(item, count++).ConfigureAwait(false); } } - while (await reader.WaitToReadOrCancelAsync(cancellationToken).ConfigureAwait(false)); + while (await reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false)); } - return index; + return count; } /// @@ -250,7 +250,7 @@ public static ValueTask ReadUntilCancelled(this ChannelReader reader (e, i) => { receiver(e, i); - return new ValueTask(); + return default; }, deferredExecution); @@ -297,7 +297,7 @@ public static ValueTask ReadUntilCancelled(this ChannelReader reader (e, _) => { receiver(e); - return new ValueTask(); + return default; }, deferredExecution); @@ -356,7 +356,7 @@ public static ValueTask ReadAllAsEnumerables(this ChannelReader reader, e => { receiver(e); - return new ValueTask(); + return default; }, deferredExecution, cancellationToken); @@ -396,7 +396,7 @@ public static async ValueTask ReadAllAsEnumerablesAsync(this ChannelReader return; } - while (await reader.WaitToReadOrCancelAsync(cancellationToken).ConfigureAwait(false)) + while (await reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false)) { await receiver(reader.ReadAvailable(cancellationToken)).ConfigureAwait(false); } @@ -775,7 +775,7 @@ public static ValueTask ReadAll(this ChannelReader reader, .ReadAllAsync((e, i) => { receiver(e, i); - return new ValueTask(); + return default; }, deferredExecution, cancellationToken); @@ -894,7 +894,7 @@ public static ValueTask ReadAll(this ChannelReader reader, (e, _) => { receiver(e); - return new ValueTask(); + return default; }, deferredExecution, cancellationToken); diff --git a/Open.ChannelExtensions/Extensions.ReadConcurrently.cs b/Open.ChannelExtensions/Extensions.ReadConcurrently.cs index 490a70d..7a30950 100644 --- a/Open.ChannelExtensions/Extensions.ReadConcurrently.cs +++ b/Open.ChannelExtensions/Extensions.ReadConcurrently.cs @@ -177,7 +177,7 @@ public static Task ReadAllConcurrently(this ChannelReader reader, e => { receiver(e); - return new ValueTask(); + return default; }, cancellationToken); @@ -321,7 +321,7 @@ public static Task ReadAllConcurrentlyAsEnumerables(this ChannelReader rea e => { receiver(e); - return new ValueTask(); + return default; }, cancellationToken); } diff --git a/Open.ChannelExtensions/Extensions.Write.cs b/Open.ChannelExtensions/Extensions.Write.cs index 3fff867..9380ed0 100644 --- a/Open.ChannelExtensions/Extensions.Write.cs +++ b/Open.ChannelExtensions/Extensions.Write.cs @@ -35,7 +35,7 @@ await target .ConfigureAwait(false); long count = 0; - var next = new ValueTask(); + ValueTask next = default; foreach (ValueTask e in source) { T? value = await e.ConfigureAwait(false); @@ -340,7 +340,7 @@ await target .ConfigureAwait(false); long count = 0; - var next = new ValueTask(); + ValueTask next = default; await foreach (T? value in source) { await next.ConfigureAwait(false); diff --git a/Open.ChannelExtensions/Extensions.WriteConcurrently.cs b/Open.ChannelExtensions/Extensions.WriteConcurrently.cs index 3d69a28..60ee24f 100644 --- a/Open.ChannelExtensions/Extensions.WriteConcurrently.cs +++ b/Open.ChannelExtensions/Extensions.WriteConcurrently.cs @@ -78,7 +78,7 @@ async Task WriteAllAsyncCore() { await shouldWait.ConfigureAwait(false); long count = 0; - var next = new ValueTask(); + ValueTask next = default; bool potentiallyCancelled = true; // if it completed and actually returned false, no need to bubble the cancellation since it actually completed. while (!errorToken.IsCancellationRequested && !cancellationToken.IsCancellationRequested @@ -88,7 +88,7 @@ async Task WriteAllAsyncCore() await next.ConfigureAwait(false); count++; next = target.TryWrite(value) // do this to avoid unnecessary early cancel. - ? new ValueTask() + ? default : target.WriteAsync(value, cancellationToken); } await next.ConfigureAwait(false); diff --git a/Open.ChannelExtensions/Extensions._.cs b/Open.ChannelExtensions/Extensions._.cs index f494ea8..817bc7f 100644 --- a/Open.ChannelExtensions/Extensions._.cs +++ b/Open.ChannelExtensions/Extensions._.cs @@ -65,7 +65,7 @@ static async ValueTask ThrowChannelClosedExceptionIfFalse(ValueTask write, internal static ValueTask CancelAsync(this CancellationTokenSource source) { source.Cancel(); - return new ValueTask(); + return default; } #endif @@ -174,7 +174,7 @@ public static ValueTask WaitToWriteAndThrowIfClosedAsync(this ChannelWritergit true true - 8.4.0 + 8.4.1 Added .Merge, .PipeAsync, and .PropagateCompletion extensions. MIT true