【问题标题】:Cancel task inside route取消路线内的任务
【发布时间】:2016-08-15 05:42:12
【问题描述】:

我正在使用 Nancy API 构建一个 C# 应用程序。我有一个异步操作,它运行一个非常长的优化算法,有时需要由用户取消。伪代码如下:

        Get["/algorithm/run/", true] = async (parameters, ct) =>
        {
                var algy = new Algorithm();
                var result = await Task.Run(() => algy.RunAlgorithm(ct), ct);
        };

我该如何去取消CancellationToken (ct),或者创建一个新的取消算法的方法?

我尝试过的另一种方法是:

var cts = new CancellationTokenSource();     
var cToken = cts.Token;

    Get["/algorithm/run/", true] = async (parameters, ct) =>
    {
      var algy = new Algorithm();
      var result = await Task.Run(() => algy.RunAlgorithm(cToken), cToken);
    };


    Get["/schedule/stop"] = _ =>
    {
        cts.Cancel();
    };

但这显然行不通,因为路由在它自己的异步任务中。

我已阅读此处发布的文章:http://blog.jonathanchannon.com/2013/08/24/async-route-handling-with-nancy/ 其中提到:

传入了 CancellationToken,因此您可以检查 ct.IsCancellationRequested 属性以确定是否要在路由处理程序中协同取消处理。例如,如果存在内部错误,或者如果某个中间件决定取消请求,或者主机正在关闭,则可以设置此属性。如果您不知道 Nancy 符合 OWIN 标准,并且自 OWIN 规范问世以来一直如此。

任何帮助将不胜感激,因为我是处理线程的新手。

完整示例:

using Nancy;
using Nancy.Hosting.Self;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace NancyApp
{
class Program
{
    private static NancyHost NancyHost { get; set; }
    private static HttpClient Client { get; set; }

    static void Main(string[] args)
    {
        var configuration = new HostConfiguration()
        {
            UrlReservations = new UrlReservations() { CreateAutomatically = true }
        };

        NancyHost = new NancyHost(configuration, new Uri("http://localhost:1234"));

        NancyHost.Start();

        Client = new HttpClient();
        Client.Timeout = new TimeSpan(1, 0, 0);
        Client.BaseAddress = new Uri("http://localhost:1234");

        Console.WriteLine("Hosting...\n");

        Client.GetAsync("http://localhost:1234/run");
        System.Threading.Thread.Sleep(5000);
        Client.GetAsync("http://localhost:1234/cancel");
        Console.ReadLine();
    }
}

public class TestModule : NancyModule
{
    CancellationTokenSource cts = new CancellationTokenSource();

    public TestModule()
    {
        Get["/run", true] = async (parameters, ct) =>
        {
            Algorithm ag = new Algorithm();
            Console.Write("Running Algorithm...\n");
            var result = await Task.Run(() => ag.RunAlgorithm(cts.Token), cts.Token);

            return Response.AsText(result.ToString());
        };

        Get["/cancel"] = _ =>
        {
            Console.Write("Cancel requested recieved\n");
            cts.Cancel();
            return Response.AsText("Foo");
        };

    }
}

class Algorithm
{
    public Algorithm()
    {

    }

    public int RunAlgorithm(CancellationToken cToken)
    {
        int min = Int32.MinValue;

        while (min < Int32.MaxValue)
        {
            if (!cToken.IsCancellationRequested)
            {
                min++;
            }
            else
            {
                Console.Write("IsCancellationRequested true!\n");
                cToken.ThrowIfCancellationRequested();
            }
        }
        return min;
    }
}
}

【问题讨论】:

  • 我不认识南希,但看起来它有自己的令牌传递给你。不过,您不必限制自己只检查一个令牌。您可以使用它传递的那个 您创建的那个,如果设置了 either 则取消。如果您需要更多详细信息,您可能应该改进这个问题,以便它包含一个好的minimal reproducible example,这样就很清楚您具体遇到了什么问题。在上面的代码示例中,我没有看到任何看起来特别明显的障碍。请注意,您可以使用CreateLinkedTokenSource() 来简化同时使用两个令牌。
  • 在第二个示例中更清楚:虽然我确实认为这会起作用,但当我调用 cts.Cancel() 时,当我在 algy.RunAlgorithm 中调用 cToken.IsCancellationRequested 时,cToken 对象永远不会返回 true (cToken)。
  • “当我调用 cts.Cancel() 时,当我在 algy.RunAlgorithm(cT‌​oken) 中调用 cToken.IsCancellatio‌​nRequested 时,cToken 对象永远不会返回 true” -- 这不合理,当然,如果你相信这就是发生的事情,那么真正必须得到可靠再现该行为的良好minimal reproducible example 支持的声明。您更有可能只认为您取消了传递给RunAlgorithm() 的同一个令牌,而是在处理两个不同的令牌。但如果没有好的 MCVE,就无法建议如何解决问题。
  • 再次,我对 Nancy 不够熟悉,无法权威地判断代码。但是有两件事很突出:首先,在我的 PC 上,我可以在调用取消操作之前等待的 5 秒内从 int.MinValue 迭代到 int.MaxValue。其次,您确定 Nancy 只创建了一个 TestModule 实例吗?如果将 cts 设为 static 字段会怎样?
  • 顺便说一句,您可能还想阅读stackoverflow.com/q/33764366/251311

标签: c# task nancy cancellation cancellationtokensource


【解决方案1】:

工作更正:

public class TestModule : NancyModule
{
    static CancellationTokenSource cts = new CancellationTokenSource();
    static CancellationToken cToken = cts.Token;

    public TestModule()
    {
        Get["/run", true] = async (parameters, ct) =>
        {
            Algorithm ag = new Algorithm();
            Console.Write("Running Algorithm...\n");
            var result = await Task.Run(() => ag.RunAlgorithm(cToken), cToken);

            return Response.AsText(result.ToString());
        };

        Get["/cancel"] = _ =>
        {
            Console.Write("Cancel requested recieved\n");
            cts.Cancel();
            cts.Dispose();
            cts = new CancellationTokenSource();
            cToken = cts.Token;
            return Response.AsText("Cancelled!");
        };
    }
}

感谢@Peter Duniho 的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多