跟踪已完成/正在运行的System.Threading.Tasks.Task对象

时间:2012-08-18 13:07:18

标签: c# .net

我正在编写一个接收消息/请求并以异步方式执行它们的Windows服务 - 它不需要等待项目完成,也不需要关心结果。我使用System.Threading.Tasks.Task成功地将请求作为任务执行。大多数这些项目执行得很快(不到一秒钟),但有些需要更长时间(2-3分钟)。

作为一个Windows服务,我需要响应“停止”命令,一些任务仍将运行。最好不要取消任务,因为运行时间较长的任务可能会使数据处于错误状态(并且回滚非常棘手)。

处理此问题的最佳方法是什么?我想保留一份我已经开始的任务列表,以便我可以做一个WaitAll。在执行服务期间,它将处理数万个请求。我如何知道何时从列表中删除已完成的任务,以便列表不会疯狂增长?我认为我不应该持有对那么多Task对象的引用。

提前致谢。

2 个答案:

答案 0 :(得分:1)

您可以将CancellationToken用于此目的。 一旦发生OnStop事件,您只需在Cancel()上调用方法CancellationTokenSource,它将传播到您传递令牌的所有任务。 如何正确取消任务有几种技巧。 如果请求取消,您可以在任务内部不时地明确检查。 或者我相信在令牌本身上有一个属性ThrowWhenCancelled,如果已经请求取消,则令牌将抛出CancellationException

如果您不关心任务结果,但希望拥有跟踪列表,请将List<Task<T>>(或可能是ConcurrentBag<Task<T>>)保留为本地变量。不时开始另一项任务,该任务将通过列表并检查Task.Status属性,如果它正在运行或其他。

只要您正确地维护这些引用,我不认为保留许多引用应该是一个问题。 此外,这取决于您希望如何停止您的应用程序。如果你和应用程序一起被杀死的任务很好,你可能根本不跟踪它们(除非它们拥有一些资源来保存,你需要释放它们)。但在大多数情况下,我会说它应该正确定型。

编辑:重读你的帖子。 RequestAdditionalTime调用可能会帮助您等待长时间运行任务完成。 在MSDN上查看:ServiceBase.RequestAdditionalTime Method

答案 1 :(得分:1)

如果您只关心在服务终止前完成的任务,我建议您使用Thread代替Task

new Thread(WorkerMethod).Start();

以这种方式创建的线程是一个所谓的前台线程,并且在所有前台线程结束之前,您的应用程序(服务)不会结束。您需要确保所有前台线程都不会在任何条件下挂起,否则您的应用程序将永远不会自行终止。您可以使用Task实现相同的目标,但是您需要保留已运行的所有任务的列表,并使用Task.WaitAll等待所有这些任务在Stop事件中完成。

如果你需要控制你的线程(即保持对它们的引用),你需要使用某种集合。

List<Thread> threads = new List<Thread>();
Thread thrd;
threads.Add(thrd = new Thread(WorkerMethod));
thrd.Start();

但是如果你真的需要控制和取消你的任务/线程,你应该选择Task,这样可以更容易取消。