是否有可能等待未知的任务完成?
使用.NET任务并行库,是否有内置的方式来等待所有正在运行的任务完成,而没有实际参考任务?是否有可能等待未知的任务完成?
Task.WaitAny()
和Task.WaitAll()
都需要一个Task
实例的数组。我想要的是类似于Task.WaitAll()
的东西,它不接受任何参数,只是等待我的应用程序产生的任何和所有任务完成。
如果没有,我会在我的框架中构建一些东西,但如果我能帮到的话,我不想重新发明轮子。
因为任何.NET代码都可以产生任何Task
(即BCL,某些图书馆等),您可能不希望等待所有未完成的任务,而只是您自己的代码创建的那些任务。最简单的方法是创建自己的工厂,使用的底层一个跟踪所有未完成的任务,并暴露出所需的等待函数
public class MyTaskFactory {
private HashSet<Task> _tasks = new HashSet<Task>();
public Task<T> StartNew<T>(Func<T> func) {
var t = Task.Factory.StartNew(func);
t.ContinueWith(x => {
lock(_tasks) {
_tasks.Remove(x);
}
});
lock(_tasks) {
_tasks.Add(t);
}
return t;
}
// ... implement other StartNew overrides ...
public void WaitAll() {
Task[] tasks;
lock(_tasks) {
tasks = _tasks.ToArray();
}
Task.WaitAll(tasks);
}
}
我做了一些与此类似的事情,但我允许我的类保持自己的任务列表,并实现您编写的同一个WaitAll()方法,该方法由IUsesTasks接口公开。这符合我目前的框架。但是,我也喜欢你的想法,可能比我的想法更多。 +1。 –
我接受了这个,因为我最终做了类似的事情,而且我喜欢't.ContinueWith(x => _tasks.Remove(x));',我没有想到。谢谢。 –
此代码不是线程安全的。例如,如果'StartNew'被并行任务调用,可能会尝试对不是线程安全的容器并行调用'Remove'或'Add'。另外,如果任务在调用WaitAll期间结束,可以同时将'Remove'调用到'ToArray'。这些问题可以通过锁定或使用线程安全的集合而不是HashSet来解决,但也存在更多细微的问题:例如,如果您当前正在等待的其中一项任务调用“StartNew”,那么您会有一个“泄漏”的任务。 –
我知道这并不直接回答你的问题,但你可以改变你的架构,因此所有的任务都是作为一个“主要”任务的子节点创建的。等待这个“主要”任务将自动等待所有的孩子。
您可以创建一个子任务是这样的:
Task.Factory.StartNew(
() => /* ... */,
TaskCreationOptions.AttachedToParent
);
您可能会发现下面的链接有用的,当它涉及到的子任务的题目是:
这是一个整洁的想法 - 我会考虑它。谢谢。 +1 –
通过“所有正在运行的任务,”做你的意思是你在你的进程/应用程序创建的任务? – n8wrl
@ n8wrl:我说过“我的应用程序产生的任何和所有任务”......所以是的。 –