【发布时间】: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(cToken) 中调用 cToken.IsCancellationRequested 时,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