等待更改列表任务
本文关键字:任务 列表 等待 | 更新日期: 2023-09-27 18:03:13
更新,更清楚地解释
我有一个运行许多任务的应用程序。有些是最初创建的,其他可以稍后添加。我需要需要一个编程结构,将等待所有的任务完成。当所有的任务完成后,应该运行一些其他的代码来清理这些东西,并对其他任务生成的数据进行一些最后的处理。
我想出了一种方法来做这件事,但不能称之为优雅。所以我想看看是否有更好的方法。
我所做的是在ConcurrentBag(线程安全集合)中保持任务列表。在这个过程的开始,我创建并添加了一些任务到ConcurrentBag。如果创建了一个需要在最后步骤之前完成的新任务,那么进程也会执行它的任务,我也将它添加到ConcurrentBag中。
任务。Wait接受task数组作为其参数。我可以将ConcurrentBag转换为一个数组,但该数组不包含在Task之后添加到Bag中的任何Task。等待被调用
在do while循环中有两步等待过程。在循环体中,我执行一个简单的Task。等待从Bag生成的数组。当它完成时,意味着所有原始任务都完成了。然后在while测试中,我对从ConcurrentBag生成的新数组进行了1毫秒的快速测试。如果没有添加新任务,或者有新任务已经完成,它将返回true,因此not条件退出循环。
如果返回false(因为添加了一个未完成的新任务),我们返回并执行一个非定时的task . wait。然后冲洗并重复,直到所有新的和旧的任务都完成。
// defined on the class, perhaps they should be properties
CancellationTokenSource Source = new CancellationTokenSource();
CancellationToken Token = Source.Token;
ConcurrentBag<Task> ToDoList = new ConcurrentBag<Task>();
public void RunAndWait() {
// start some tasks add them to the list
for (int i = 0; i < 12; i++)
{
Task task = new Task(() => SillyExample(Token), Token);
ToDoList.Add(task);
task.Start();
}
// now wait for those task, and any other tasks added to ToDoList to complete
try
{
do
{
Task.WaitAll(ToDoList.ToArray(), Token);
} while (! Task.WaitAll(ToDoList.ToArray(), 1, Token));
}
catch (OperationCanceledException e)
{
// any special handling of cancel we might want to do
}
// code that should only run after all tasks complete
}
是否有更优雅的方法来做到这一点?
我建议使用ConcurrentQueue
并在等待它们时删除项目。由于队列的先进先出特性,如果您到达队列中没有任何剩余的点,您知道您已经等待了所有已添加到该点的任务。
ConcurrentQueue<Task> ToDoQueue = new ConcurrentQueue<Task>();
...
while(ToDoQueue.Count > 0 && !Token.IsCancellationRequested)
{
Task task;
if(ToDoQueue.TryDequeue(out task))
{
task.Wait(Token);
}
}
这是一个非常酷的使用微软的响应式框架(NuGet "Rx-Main")的方法。
var taskSubject = new Subject<Task>();
var query = taskSubject.Select(t => Observable.FromAsync(() => t)).Merge();
var subscription =
query.Subscribe(
u => { /* Each Task Completed */ },
() => Console.WriteLine("All Tasks Completed."));
现在,要添加任务,只需这样做:
taskSubject.OnNext(Task.Run(() => { }));
taskSubject.OnNext(Task.Run(() => { }));
taskSubject.OnNext(Task.Run(() => { }));
然后表示完成:
taskSubject.OnCompleted();
值得注意的是,信令完成不会立即完成查询,它也将等待所有任务完成。信号完成只是表示您将不再添加任何新任务。
最后,如果你想取消,那么就这样做:
subscription.Dispose();