繁体   English   中英

Parallel.ForEachAsync 任务与 ValueTask

[英]Parallel.ForEachAsync Task vs ValueTask

我正在尝试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}");

快速搜索只产生了使用带有多个语句的 lambda 的 ForEachAsync 示例: async (x, ct) => { ...; await ...; } async (x, ct) => { ...; await ...; } async (x, ct) => { ...; await ...; }

我觉得

body: async (item, cancellationToken) => await WorkAsync(item, cancellationToken).ConfigureAwait(false));

明显比:

body: WorkAsync);

在这里的简单示例中,我显然可以更改 worker 方法的返回类型,但修改现有代码以返回ValueTask似乎是不明智的。

使用Parallel.ForEachAsync创建漂亮的代码时,我是否错过了一个明显的解决方案?

我不知道它是否更漂亮,但你可以考虑这样做:

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);

老实说,我认为Parallel.ForEachAsync API 如果接受Func<T, CancellationToken, Task>委托作为body会更好,因为该 API 最常见的使用场景是高延迟 I/O 绑定操作网络。 对于这些场景,从Task切换到ValueTask在性能或内存效率方面几乎为零。 降低 API 的一般可用性以使用IValueTaskSource支持的body委托来优化一些奇异的场景,这对我来说毫无意义。 但这就是我们现在所拥有的,而且肯定比我们之前拥有的要漂亮得多,所以我并没有过多抱怨。 😃

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM