我正在编写一个接收消息/请求并以异步方式执行它们的Windows服务 - 它不需要等待项目完成,也不需要关心结果。我使用System.Threading.Tasks.Task成功地将请求作为任务执行。大多数这些项目执行得很快(不到一秒钟),但有些需要更长时间(2-3分钟)。
作为一个Windows服务,我需要响应“停止”命令,一些任务仍将运行。最好不要取消任务,因为运行时间较长的任务可能会使数据处于错误状态(并且回滚非常棘手)。
处理此问题的最佳方法是什么?我想保留一份我已经开始的任务列表,以便我可以做一个WaitAll。在执行服务期间,它将处理数万个请求。我如何知道何时从列表中删除已完成的任务,以便列表不会疯狂增长?我认为我不应该持有对那么多Task对象的引用。
提前致谢。
答案 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
,这样可以更容易取消。