有相当于 Task.WhenAll
验收 ValueTask
?
我可以使用它来解决它
Task.WhenAll(tasks.Select(t => t.AsTask()))
如果它们都包装好,那就没关系了 Task
但它会迫使无用的分配 Task
真实的对象 ValueTask
。
有相当于 Task.WhenAll
验收 ValueTask
?
我可以使用它来解决它
Task.WhenAll(tasks.Select(t => t.AsTask()))
如果它们都包装好,那就没关系了 Task
但它会迫使无用的分配 Task
真实的对象 ValueTask
。
按设计,没有。从 文档:
方法可能会返回此值类型的实例,因为它们的操作结果可能同步可用,并且预计会频繁调用该方法,以致为每个调用分配新任务的成本将过高。
...
例如,考虑一个可以返回a的方法
Task<TResult>
将缓存任务作为常见结果或aValueTask<TResult>
。如果结果的消费者想要将其用作Task<TResult>
,比如在方法中使用Task.WhenAll
和Task.WhenAny
,ValueTask<TResult>
首先需要转换为Task<TResult>
运用AsTask
,这导致了一个在缓存时可以避免的分配Task<TResult>
最初是用过的。因此,任何异步方法的默认选择应该是返回a
Task
要么Task<TResult>
。只有当性能分析证明它值得时才应该ValueTask<TResult>
用来代替Task<TResult>
。
正如@stuartd指出的那样,设计不支持它,我必须手动实现:
public static async Task<IReadOnlyCollection<T>> WhenAll<T>(this IEnumerable<ValueTask<T>> tasks)
{
var results = new List<T>();
var toAwait = new List<Task<T>>();
foreach (var valueTask in tasks)
{
if (valueTask.IsCompletedSuccessfully)
results.Add(valueTask.Result);
else
toAwait.Add(valueTask.AsTask());
}
results.AddRange(await Task.WhenAll(toAwait).ConfigureAwait(false));
return results;
}
当然,这仅对高吞吐量和高数量有帮助 ValueTask
因为它增加了一些其他开销。
注意:正如@StephenCleary指出的那样,这不会保持顺序为 Task.WhenAll
如果需要,可以很容易地改变它来实现它。