[英]Parallel.ForEachAsync Task vs ValueTask
I'm trying out Parallel.ForEachAsync
and the compiler is kind enough to inform me that the body is a func that returns a ValueTask
, not a Task
.我正在尝试
Parallel.ForEachAsync
并且编译器很友好地告诉我 body 是一个返回ValueTask
的函数,而不是Task
。
Stopwatch sw = Stopwatch.StartNew();
var numbers = Enumerable.Range(start: 0, count: 10);
// Error: 'Task WorkAsync(int, CancellationToken)' has the wrong return type
await Parallel.ForEachAsync(
source: numbers,
parallelOptions: new ParallelOptions{ MaxDegreeOfParallelism = 2 },
body: WorkAsync);
async Task WorkAsync(int item, CancellationToken cancellationToken)
{
WriteLine($"Task {item} Start");
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken).ConfigureAwait(false);
WriteLine($"Task {item} End");
}
void WriteLine(string s) => Console.WriteLine($"{sw.ElapsedMilliseconds, 3} Thread{Thread.CurrentThread.ManagedThreadId}: {s}");
A quick search yielded only ForEachAsync examples that use a lambda with multiple statements: async (x, ct) => { ...; await ...; }
快速搜索只产生了使用带有多个语句的 lambda 的 ForEachAsync 示例:
async (x, ct) => { ...; await ...; }
async (x, ct) => { ...; await ...; }
async (x, ct) => { ...; await ...; }
. async (x, ct) => { ...; await ...; }
。
I feel that我觉得
body: async (item, cancellationToken) => await WorkAsync(item, cancellationToken).ConfigureAwait(false));
is significantly uglier than:明显比:
body: WorkAsync);
In the trivial example here I can obviously change the return type of the worker method, but it seems unwise to modify existing code to return ValueTask
s.在这里的简单示例中,我显然可以更改 worker 方法的返回类型,但修改现有代码以返回
ValueTask
似乎是不明智的。
Is there an obvious solution I have missed for creating beautiful code with Parallel.ForEachAsync
?使用
Parallel.ForEachAsync
创建漂亮的代码时,我是否错过了一个明显的解决方案?
I don't know if it qualifies as prettier, but you could consider doing this:我不知道它是否更漂亮,但你可以考虑这样做:
await Parallel.ForEachAsync(
source: numbers,
parallelOptions: new ParallelOptions { MaxDegreeOfParallelism = 2 },
body: ToValueTaskResult<int>(WorkAsync));
static Func<T, CancellationToken, ValueTask> ToValueTaskResult<T>(
Func<T, CancellationToken, Task> function)
=> async (item, ct) => await function(item, ct).ConfigureAwait(false);
To be honest I think that the Parallel.ForEachAsync
API would be better if it accepted a Func<T, CancellationToken, Task>
delegate as the body
, since the most common usage scenarios for this API are high latency I/O-bound operations over the network.老实说,我认为
Parallel.ForEachAsync
API 如果接受Func<T, CancellationToken, Task>
委托作为body
会更好,因为该 API 最常见的使用场景是高延迟 I/O 绑定操作网络。 For these scenarios, switching from Task
to ValueTask
makes practically zero difference, in either performance or memory-efficiency.对于这些场景,从
Task
切换到ValueTask
在性能或内存效率方面几乎为零。 Reducing the general usability of the API in order to optimize some exotic scenarios with IValueTaskSource
-backed body
delegates, makes little sense to me.降低 API 的一般可用性以使用
IValueTaskSource
支持的body
委托来优化一些奇异的场景,这对我来说毫无意义。 But this is what we have now, and it's certainly much prettier than what we had earlier , so I am not complaining too much.但这就是我们现在所拥有的,而且肯定比我们之前拥有的要漂亮得多,所以我并没有过多抱怨。 😃
😃
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.