是否有通用的Task.WaitAll?

Cri*_*scu 60 c# generics covariance task-parallel-library

我启动了一些并行任务,如下所示:

var tasks =
    Enumerable.Range(1, 500)
    .Select(i => Task.Factory.StartNew<int>(ProduceSomeMagicIntValue))
    .ToArray();
Run Code Online (Sandbox Code Playgroud)

然后加入他们

Task.WaitAll(tasks);
Run Code Online (Sandbox Code Playgroud)

在最后一行,我得到一个蓝色波浪形标记tasks,并带有警告信息:

__PRE__

我理解为什么我会收到这条消息,但有没有办法解决这个问题呢?(例如,像通用版本Task.WaitAll()?)

Mer*_*OWA 28

Task.WaitAll的一般方法意味着所有任务都必须返回相同的类型,这种类型的用处非常有限.写这样的东西可以手动完成(参见Bas Brekelmans的答案),但这不允许ContinueWith或取消没有很多工作.

一个简单的解决方案,如果你没有使用该数组的其他任何东西是

  .ToArray<Task>();
Run Code Online (Sandbox Code Playgroud)


DMa*_*yer 28

我很确定这是一个安全的操作,即使有警告,但如果你真的想绕过它比创建自己的实现更好的选择只是将你的tasks参数转换为它想要的类型:

Task.WaitAll(tasks.Cast<Task>().ToArray())
Run Code Online (Sandbox Code Playgroud)

为我杀死了蓝色的波浪线,让我保持我的tasks变量通用,并没有强迫我创建一大堆新的可怕代码,这些代码最终是不必要的.


Bas*_*Bas 7

您可以创建一个扩展方法来执行此操作.

我不知道WaitAll的确切实现,但我们可以假设它等待每个项目完成:

static class TaskExtensions
{
    public static void WaitAll<T>(this Task<T>[] tasks)
    {
        foreach (var item in tasks)
        {
            item.Wait();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后从您当前的代码中调用:

tasks.WaitAll();
Run Code Online (Sandbox Code Playgroud)

编辑

实际实现有点复杂.我已经省略了这个答案的代码,因为它相当长.

http://pastebin.com/u30PmrdS

您可以修改它以支持通用任务.

  • “实际实施”非常重要。更不用说,如果 .NET Framework 实现有任何错误修复或性能改进,您就会失去(或需要重新编码)。@MerickOWA 和 DMac the Destroyer(按此顺序)的解决方案非常简单地解决了 OP 的问题。 (2认同)
  • 这显然是错误的——你在这里*串行*运行你的任务,这不是真正的“WaitAll”所做的。 (2认同)
  • 如果人们坚持构建自己的(而不是使用将通用集合转换为任务数组的其他解决方案之一),这是一个更好的源,其中包含完整的注释和指向您还需要的所有内部代码的链接复制以使其工作:https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,72b6b3fa5eb35695 (2认同)

Yit*_*hak 5

更好,更简单的答案

其实有IS仿制出类似超载:

Task all = Task.WhenAll(tasks)
Run Code Online (Sandbox Code Playgroud)

这是不同的,它返回一个Task将在所有任务完成后完成的操作。因此您可以随便await在其上使用,或Wait()

看一下签名:

超载

---------非常规过载--------------

WhenAll(IEnumerable<Task>) 创建一个将Task在可枚举集合中的所有对象均完成后完成的任务。

WhenAll(Task[]) 创建一个任务,该任务将Task在数组中的所有 对象均已完成时完成。

---------一般超载 --------------

WhenAll<TResult>(IEnumerable<Task<TResult>>) 创建一个将Task<TResult>在可枚举集合中的所有对象均完成后完成的任务。

WhenAll<TResult>(Task<TResult>[]) 创建一个任务,该任务将Task<TResult>在数组中的所有对象均已完成时完成。