【问题标题】:Tracking completed/running System.Threading.Tasks.Task objects跟踪已完成/正在运行的 System.Threading.Tasks.Task 对象
【发布时间】:2017-10-04 06:14:34
【问题描述】:

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

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

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

提前致谢。

【问题讨论】:

    标签: c# .net


    【解决方案1】:

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

    如果你不关心任务结果,但想有一个跟踪列表,只需将List<Task<T>>(或者可能是ConcurrentBag<Task<T>>)作为局部变量。不时启动另一个任务,该任务将遍历列表并检查 Task.Status 属性,如果它正在运行或其他。

    只要您正确维护这些引用,我认为保留这么多引用应该不是问题。 此外,这取决于您要如何停止应用程序。如果您对与应用程序一起被杀死的任务感到满意,您可能根本不会跟踪它们(除非它们持有一些要持有的资源,并且您需要释放它们)。但在大多数情况下,我会说它应该正确完成。

    编辑:只需重读您的帖子。 RequestAdditionalTime 电话可以帮助您等到长时间运行的任务完成。 在 MSDN 上查看:ServiceBase.RequestAdditionalTime Method

    【讨论】:

      【解决方案2】:

      如果您只关心在服务终止之前完成的任务,我建议您使用 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,这样可以更轻松地取消。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-01
        • 2012-02-09
        • 1970-01-01
        相关资源
        最近更新 更多