我开始执行一些并行任务,例如:
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()
的通用版本?)
答案 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();
修改强>
实际实施有点复杂。我已经省略了这个答案的代码,因为它相当长。
您可以修改此项以支持通用任务。
答案 3 :(得分:1)
实际上, IS 有类似的泛型过载:
Task all = Task.WhenAll(tasks)
不同之处在于,它返回Task
,该任务将在所有任务完成后完成。因此您可以根据需要使用await
或Wait()
。
查看签名:
超载
---------非常规过载--------------
WhenAll(IEnumerable<Task>)
创建一个任务,该任务将 当可枚举集合中的所有Task
个对象都具有 完成。
WhenAll(Task[])
创建一个任务,该任务将在所有 数组中的Task
个对象已完成。--------- 一般过载 --------------
WhenAll<TResult>(IEnumerable<Task<TResult>>)
创建一个任务,该任务将 当所有Task<TResult>
对象都可枚举时完成 收集已完成。
WhenAll<TResult>(Task<TResult>[])
创建将完成的任务 数组中的所有Task<TResult>
对象都完成后。