完成后如何从集合中删除任务
本文关键字:集合 删除 任务 | 更新日期: 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.Count
和foreach (DataItem item in sources)
查看未处理的项目。(与您的解决方案不同的是,您看不到当前正在处理的项目)
使用 ContinueWith 设置从集合中删除任务的操作。