Skip to content

Commit 7f314be

Browse files
Avoid potential allocation when using lambdas.
1 parent 965379e commit 7f314be

6 files changed

Lines changed: 35 additions & 110 deletions

File tree

Open.ChannelExtensions/BatchingChannelReader.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ public BatchingChannelReader(
4141
/// </summary>
4242
public bool ForceBatch() => TryPipeItems(true);
4343

44+
void ForceBatch(object obj) => ForceBatch();
45+
4446
long _timeout = -1;
4547
Timer? _timer;
4648

@@ -67,7 +69,7 @@ public BatchingChannelReader<T> WithTimeout(long millisecondsTimeout)
6769
}
6870

6971
LazyInitializer.EnsureInitialized(ref _timer,
70-
() => new Timer(obj => ForceBatch()));
72+
() => new Timer(ForceBatch));
7173

7274
if (_batch is null) return this;
7375

Open.ChannelExtensions/Documentation.xml

Lines changed: 2 additions & 102 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Open.ChannelExtensions/Extensions.Pipe.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@ public static async ValueTask<long> PipeTo<T>(this ChannelReader<T> source,
2828
if (target is null) throw new ArgumentNullException(nameof(target));
2929
Contract.EndContractBlock();
3030

31+
// Acceptable closure.
32+
ValueTask WriteTarget(T e) => target.WriteAsync(e, cancellationToken);
33+
3134
try
3235
{
33-
return await source.ReadAllAsync(e => target.WriteAsync(e, cancellationToken), cancellationToken).ConfigureAwait(false);
36+
return await source.ReadAllAsync(WriteTarget, cancellationToken).ConfigureAwait(false);
3437
}
3538
catch (Exception ex)
3639
{

Open.ChannelExtensions/Extensions.Write.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Collections.Generic;
33
using System.Diagnostics.Contracts;
44
using System.IO;
5-
using System.Linq;
65
using System.Threading;
76
using System.Threading.Channels;
87
using System.Threading.Tasks;
@@ -108,7 +107,7 @@ public static ValueTask<long> WriteAllAsync<T>(
108107

109108
return WriteAllAsync(
110109
target,
111-
source.Select(e => new ValueTask<T>(e)),
110+
source.WrapValueTask(),
112111
complete,
113112
deferredExecution,
114113
cancellationToken);
@@ -155,7 +154,7 @@ public static ValueTask<long> WriteAllAsync<T>(
155154

156155
return WriteAllAsync(
157156
target,
158-
source.Select(e => new ValueTask<T>(e())),
157+
source.WrapValueTask(),
159158
complete,
160159
deferredExecution,
161160
cancellationToken);
@@ -202,7 +201,7 @@ public static ValueTask<long> WriteAll<T>(
202201

203202
return WriteAllAsync(
204203
target,
205-
source.Select(e => new ValueTask<T>(e)),
204+
source.WrapValueTask(),
206205
complete,
207206
deferredExecution,
208207
cancellationToken);
@@ -309,6 +308,8 @@ public static ValueTask<long> WriteAllLines(
309308
CancellationToken cancellationToken)
310309
=> WriteAllLines(target, source, complete, false, cancellationToken);
311310

311+
312+
312313
#if NETSTANDARD2_1
313314
/// <summary>
314315
/// Asynchronously writes all entries from the source to the channel.

Open.ChannelExtensions/Extensions.WriteConcurrently.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public static Task<long> WriteAllConcurrentlyAsync<T>(
141141
IEnumerable<Task<T>> source,
142142
bool complete = false,
143143
CancellationToken cancellationToken = default)
144-
=> WriteAllConcurrentlyAsync(target, maxConcurrency, source.Select(e => new ValueTask<T>(e)), complete, cancellationToken);
144+
=> WriteAllConcurrentlyAsync(target, maxConcurrency, source.WrapValueTask(), complete, cancellationToken);
145145

146146
/// <summary>
147147
/// Asynchronously executes all entries and writes their results to the channel.
@@ -160,5 +160,5 @@ public static Task<long> WriteAllConcurrentlyAsync<T>(
160160
IEnumerable<Func<T>> source,
161161
bool complete = false,
162162
CancellationToken cancellationToken = default)
163-
=> WriteAllConcurrentlyAsync(target, maxConcurrency, source.Select(e => new ValueTask<T>(e())), complete, cancellationToken);
163+
=> WriteAllConcurrentlyAsync(target, maxConcurrency, source.WrapValueTask(), complete, cancellationToken);
164164
}

Open.ChannelExtensions/Extensions._.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,25 @@ static async ValueTask ThrowChannelClosedExceptionIfFalse(ValueTask<bool> write,
4646
}
4747
}
4848

49+
// Avoid potential lambda allocation.
50+
internal static IEnumerable<ValueTask<T>> WrapValueTask<T>(this IEnumerable<T> source)
51+
{
52+
foreach (var e in source)
53+
yield return new ValueTask<T>(e);
54+
}
55+
56+
internal static IEnumerable<ValueTask<T>> WrapValueTask<T>(this IEnumerable<Task<T>> source)
57+
{
58+
foreach (var e in source)
59+
yield return new ValueTask<T>(e);
60+
}
61+
62+
internal static IEnumerable<ValueTask<T>> WrapValueTask<T>(this IEnumerable<Func<T>> source)
63+
{
64+
foreach (var e in source)
65+
yield return new ValueTask<T>(e());
66+
}
67+
4968
/// <summary>
5069
/// Waits for opportunity to write to a channel and throws a ChannelClosedException if the channel is closed.
5170
/// </summary>

0 commit comments

Comments
 (0)