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

nic*_*ckv 11 c# timeout task-parallel-library

我的问题是如何停止长时间运行的任务(.net 4)?我已经实现了TPL并尝试使用CancellationTokenSource,但它似乎不适用于我的场景.我见过的所有例子都假设你在while循环中工作,这样你就可以检查任务是否已被取消,而我只需要一个需要很长时间的操作.我不能等待工作完成,因为我需要假设它可能永远不会完成.这是我尝试过的代码:

        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.");
        }
Run Code Online (Sandbox Code Playgroud)

代码可以工作但是如果"超时"发生并且正在完成的工作访问"非托管代码"即资源,则永远不会处理任务.那说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();
        }
Run Code Online (Sandbox Code Playgroud)

Sti*_*gar 2

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

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