有没有通用的任务
本文关键字:任务 有没有 | 更新日期: 2023-09-27 18:30:21
我开始一些并行任务,如下所示:
var tasks =
Enumerable.Range(1, 500)
.Select(i => Task.Factory.StartNew<int>(ProduceSomeMagicIntValue))
.ToArray();
然后加入他们
Task.WaitAll(tasks);
在最后一行,我在tasks
下得到一个蓝色波浪形标记,并带有警告消息:
从任务 [] 到 任务 [] 的协变数组转换可能导致写入操作出现运行时异常。
明白为什么我会收到这条消息,但是有没有办法解决这个问题?(例如,像Task.WaitAll()
的通用版本?
Task.WaitAll 的通用方法意味着所有 Tasks 都必须返回相同的类型,这将非常有限。 写这样的事情可以手动完成(参见Bas Brekelmans的回答),但这不允许在没有大量工作的情况下继续或取消。
如果您不将数组用于其他任何用途,一个简单的解决方案是
.ToArray<Task>();
我很确定即使有警告,这也是一个安全的操作,但是如果你真的想绕过它,比创建自己的实现更好的选择就是将你的tasks
参数转换为它想要的类型:
Task.WaitAll(tasks.Cast<Task>().ToArray())
这为我杀死了蓝色波浪线,让我保持tasks
变量泛型,并且不会强迫我创建大量最终不必要的新可怕代码。
更好更简单的答案
实际上有一个类似的泛型重载:
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>
对象都已完成时。
您可以创建一个扩展方法来执行此操作。
我不知道 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
您可以修改此设置以支持通用任务。