是否有通用的Task.WaitAll?

时间:2012-04-06 13:24:24

标签: c# generics task-parallel-library covariance

我开始执行一些并行任务,例如:

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

然后加入

Task.WaitAll(tasks);

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

Co-variant array conversion from Task[] to Task[] 
can cause run-time exception on write operation.

我理解为什么我会收到这条消息,但是有办法吗? (例如,像Task.WaitAll()的通用版本?)

4 个答案:

答案 0 :(得分:28)

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

Task.WaitAll(tasks.Cast<Task>().ToArray())

为我杀死了蓝色的曲线,让我保持我的tasks变量通用,并且不会强迫我创建一大堆最终不必要的新的可怕代码。

答案 1 :(得分:25)

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

如果您没有将数组用于其他任何内容,那么这是一个简单的解决方案

  .ToArray<Task>();

答案 2 :(得分:7)

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

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

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

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

tasks.WaitAll();

修改

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

http://pastebin.com/u30PmrdS

您可以修改此项以支持通用任务。

答案 3 :(得分:1)

一个不同的答案

实际上, IS 有类似的泛型过载:

Task all = Task.WhenAll(tasks)

不同之处在于,它返回Task,该任务将在所有任务完成后完成。因此您可以根据需要使用awaitWait()

查看签名:

  

超载

     

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

     

WhenAll(IEnumerable<Task>) 创建一个任务,该任务将   当可枚举集合中的所有Task个对象都具有   完成。

     

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

     

--------- 一般过载 --------------

     

WhenAll<TResult>(IEnumerable<Task<TResult>>) 创建一个任务,该任务将   当所有Task<TResult>对象都可枚举时完成   收集已完成。

     

WhenAll<TResult>(Task<TResult>[]) 创建将完成的任务   数组中的所有Task<TResult>对象都完成后。