我正在尝试Parallel.ForEachAsync,编译器很好地告诉我,body是返回ValueTask而不是Task的func。
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 ...; }。
我觉得
body: async (item, cancellationToken) => await WorkAsync(item, cancellationToken).ConfigureAwait(false));远比以下更丑:
body: WorkAsync);在这里的简单示例中,我显然可以更改worker方法的返回类型,但是修改现有代码以返回ValueTask似乎是不明智的。
对于用Parallel.ForEachAsync创建漂亮的代码,我错过了明显的解决方案吗?
发布于 2022-06-27 02:43:24
我不知道它是否更漂亮,但你可以考虑这样做:
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-backed body委托优化一些奇异的场景,对我来说没有什么意义。但这是我们现在拥有的,它肯定比我们之前的经历漂亮得多,所以我没有抱怨太多。
https://stackoverflow.com/questions/72766329
复制相似问题