安全地停止长时间运行的任务



如何停止长时间运行的任务 (.net 4)?

我已经实现了 TPL 并尝试使用该CancellationTokenSource但它似乎不适用于我的方案。我看到的所有示例都假设您正在 while-loop 中工作,以便您可以检查任务是否已取消,而我只有一个需要很长时间的操作。我不能等待工作完成,因为我需要假设它可能永远不会完成。这是我尝试过的代码:

bool? result = null;
var cs = new CancellationTokenSource();
var ct = cs.Token;
var doWorkTask = new Task(() =>
{
    Console.WriteLine("start dowork task");
    result = Work.LongRunning();
 }, ct);
doWorkTask.Start();
Task.WaitAny(new Task[] { doWorkTask }, timetowait);
if (doWorkTask.IsCompleted)
{
    Console.WriteLine("dowork task completed");
    doWorkTask.Dispose();
}
else
{
    Console.WriteLine("dowork task has timedout");
    cs.Cancel();
    throw new TimeoutException("Timeout hit.");
}
代码

有效,但如果发生超时并且正在完成的工作访问"非托管代码"(即资源),则永远不会释放任务。也就是说,IsCancelledRequested不能用于Work.LongRunning()所以我不能ThrowIfCancellationRequested.

我对其他想法持开放态度,我也尝试过BackgroundWorker但这似乎也不合适。

新示例:

var service = new System.ServiceProcess.ServiceController(ServiceName, ServerName);
var serviceTask = Task.Factory.StartNew(() =>
{
    result = (service.Status == ServiceControllerStatus.Running
         || service.Status == ServiceControllerStatus.StartPending);
}, cs.Token);
serviceTask.Wait(2000, cs.Token);
if (!serviceTask.IsCompleted)
{
    cs.Cancel();
}

这是描述的选项 1 obove 的示例(即只是杀死任务而不发出取消信号)

class Program
    {
        private static void Main(string[] args)
        {
            Test test = new Test();
            test.Run();
            Console.WriteLine("Type c to cancel");
            if (Console.ReadLine().StartsWith("c"))
            {
                Console.WriteLine("cancellation requested");
                test.CancellationTokenSource.Cancel();
            }
            Console.ReadLine();
        }
    }
    public class Test
    {
        private void DoSomething()
        {
            Console.WriteLine("DoSomething runs for 30 seconds ");
            Thread.Sleep(new TimeSpan(0, 0, 0, 30));
            Console.WriteLine("woke up now ");
        }
        public CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
        public void Run()
        {
                var generateReportsTask = Task.Factory.StartNew(() =>
                {
                    CancellationTokenSource.Token.ThrowIfCancellationRequested();
                    Task doSomething = new Task(DoSomething, CancellationTokenSource.Token);
                    doSomething.Start();
                    doSomething.Wait(CancellationTokenSource.Token);
                }, CancellationTokenSource.Token);
                generateReportsTask.ContinueWith(
                    (t) =>
                    {
                        if (t.Exception != null)
                            Console.WriteLine("Exceptions reported :n " + t.Exception);
                        if (t.Status == TaskStatus.RanToCompletion)
                            Console.WriteLine("Completed report generation task");
                        if (t.Status == TaskStatus.Faulted)
                            Console.WriteLine("Completed reported generation with unhandeled exceptions");
                        if(t.Status == TaskStatus.Canceled)
                            Console.WriteLine("The Task Has been cancelled");
                    });
        }
    }

任务并行库专为 CPU 密集型工作而设计。CPU 密集型工作在一段时间内完成。如果你的Work.LongRunning()是CPU密集型的,你应该能够在里面传递取消令牌并取消它。如果它不是 CPU 密集型的,那么您可以简单地在最终回调中丢弃结果,而不必费心停止实际工作,因为它只是在等待。

顺便说一句,如果您有等待(数据库调用或其他东西),您可能在底部的某个地方有异步方法。您可以显示开始/结束模式并将其包装在任务中。这个问题解释了如何: TPL TaskFactory.FromAsync vs Tasks with block Method 这样,您将避免占用通用线程,因为 IO 等待是以操作系统处理的特殊方式完成的。

相关内容

  • 没有找到相关文章

最新更新