完成后如何从集合中删除任务

本文关键字:集合 删除 任务 | 更新日期: 2023-09-27 17:56:35

假设我有一个System.Threading.Tasks.Task集合:

HashSet<Task> myTasks = new HashSet<Task>();

。并且我会定期将更多内容输入到集合中,因为我有更多的数据需要处理:

foreach (DataItem item in itemsToProcess)
    myTasks.Add(
        Task.Factory.StartNew(
            () => Process(item),
            cancellationToken,
            TaskCreationOptions.LongRunning,
            TaskScheduler.Default));    

由于Task在完成后仍处于TaskStatus.RanToCompletion状态,而不仅仅是消失,因此它们将保留在集合中,直到显式删除并且集合将无限期增长。 需要修剪Task以防止这种情况。

我看过的一种方法是让Task访问该集合,并在最后将其自行删除。 但是我也在研究一种架构,在该架构中,我必须删除我的组件尚未创建的任务。 我的第一个想法是附加一个触发器或事件来完成每个任务,如下所示:

foreach (Task task in createdSomewhereElse)
{
    lock (myTasks) myTasks.Add(task);
    task.WhenTaskIsCompleted += 
        (o, ea) => { lock(myTasks) myTasks.Remove(task); };
    task.Start();
}

。但Task没有这样的事件。 有什么好方法可以完成我正在寻找的东西吗? 像这样:

完成后如何从集合中删除任务

您当然可以在任务完成时附加一个触发器:Task.ContinueWith(及其通用等效项)。这对你来说可能已经足够了。

您可能还希望将ConcurrentDictionary用作一种穷人的并发集 - 这样您在访问集合时就不必锁定。只需在迭代时使用 Keys 属性,并使用您喜欢的任何值作为值。

为什么需要将任务保留在集合中?

为什么不使用基于BlockingCollection和Parallel.ForEach的解决方案。

var sources = new BlockingCollection<DataItem>();
Task.Factory.StartNew(() => {
    Parallel.ForEach(sources.GetConsumingPartitioner(),
                     item => Process(item));
});

现在,您只需将项目输入阻止集合,它们就会被自动处理。

foreach (DataItem item in itemsToProcess)
    sources.Add(item);

您可以使用sources.Countforeach (DataItem item in sources)查看未处理的项目。(与您的解决方案不同的是,您看不到当前正在处理的项目)

使用 ContinueWith 设置从集合中删除任务的操作。