等待更改列表任务

本文关键字:任务 列表 等待 | 更新日期: 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();