C# 为什么我的任务没有取消?
我正在运行一个周期性地卷曲到URL列表的过程,以测试这些网站的性能。我的主程序基本上是一个do…sleep…while循环,它调用一个函数,每N秒运行一次测试,并通过键盘中断将其关闭。简而言之,我的代码如下:C# 为什么我的任务没有取消?,c#,task,libcurl,C#,Task,Libcurl,我正在运行一个周期性地卷曲到URL列表的过程,以测试这些网站的性能。我的主程序基本上是一个do…sleep…while循环,它调用一个函数,每N秒运行一次测试,并通过键盘中断将其关闭。简而言之,我的代码如下: public void runTest() { if(isRunning) { return; //Plus some logging that one or more of the tests hasn't completed } try {
public void runTest()
{
if(isRunning)
{
return; //Plus some logging that one or more of the tests hasn't completed
}
try {
isRunning = true;
Curl.GlobalInit((int)CURLinitFlag.CURL_GLOBAL_ALL);
CancellationTokenSource cts = new CancellationTokenSource(httpTimeoutValueMs * 2);
foreach (var url in urls)
taskList.Add(doAsyncCurls(url, cts))
List<CurlResults> listOfResults = Task.WhenAll(taskList.Select(x => x)).Result.ToList();
taskList.Clear();
}
catch {/*Some exception handling code*/}
finally {
isRunning = false;
Curl.GlobalCleanup();
}
}
private static async Task<CurlResults> doAsyncCurls(string url, CancellationTokenSource cts)
{
try
{
/*Initiate a Curl using libCurl*/
Easy easy = new Easy();
easy.SetOpt(CURLoption.CURLOPT_URL, url);
easy.SetOpt(CURLoption.CURLOPT_DNS_CACHE_TIMEOUT, 0); //Disables DNS cache
easy.SetOpt(CURLoption.CURLOPT_CONNECTTIMEOUT, httpTimeoutValueMs / 1000); //20sec timeout
Task t = new Task(() => easy.Perform(), cts.Token);
t.Start();
await t;
return new CurlResults(/*valid results parameters*/);
}
catch (TaskCanceledException)
{ /*Cancellation token invoked*/
return new CurlResults(/*Invalid results parameters*/);
}
catch (Exception e)
{ /*Other exception handling*/
return new CurlResults(/*Invalid results parameters*/);
}
doAsyncCurl函数执行它在tin上所说的操作,将http超时值设置为取消令牌的一半,这样http请求应该在调用取消令牌之前消失,并生成一个负面结果。我添加了取消令牌以尝试处理我的问题,如下所示
我让它运行了很长一段时间——首先,一切都很好,但最终数百次,如果不是更多的迭代,通过定期运行测试调用,似乎其中一个任务被卡住了,取消令牌没有被调用,而curl测试过程实际上被卡住了
除了找出哪些URL是有问题的,而且它们都是有效的,还能做些什么来诊断出哪里出了问题?或者我的平行卷发一开始就完全错了?我很感激我可以实例化上一轮已经完成的URL的新卷发,并让挂起的一个挂起,而不是等待它们全部完成后再开始新的一批,但我不担心效率的提高。取消没有自动性。您必须检查取消状态并结束执行或调用CancellationToken.ThrowIfCancellationRequested执行取消。CancellationToken将告诉您是否请求取消;取消必须由您自己完成 以下是您的问题:
Task t = new Task(() => easy.Perform(), cts.Token);
您正在将令牌传递给任务构造函数。如果在任务开始之前取消,这将对您有所帮助。一旦任务启动,执行的方法负责取消。简单。Perform不知道您的取消令牌,因此永远无法确定是否请求取消。因此,它将走到尽头
在任务执行过程中,您需要定期检查取消令牌,以实现所需目标。传递对令牌的引用并不意味着任务主体中会自动取消任务。您仍然需要定期检查它。好的-我已经总结了我的取消令牌实现,但是我也不明白为什么Curl没有超时,我应该/可以在这一行之后使用t.waittimoutMs,而不是使用令牌和wait t t?是的,你可以,但这不会结束你的任务。它将继续运行到最后。@JetSetJim如果您这样做,那么代码就不会是异步的。您可以构建一个新任务,该任务将。您可以使用类似这样的方法创建一个任务,该任务将在取消令牌时完成,但这不会阻止操作继续执行…它想做的任何事情,如果这对您来说足够的话。@Sefe-那么这是否意味着挂起任务中实例化的easy.Perform将继续存在,直到完成为止?如果它在后续调用中一直挂起,则可能是一个问题,因为没有任何东西会对其进行整理。如果它引发异常,则会导致任务出错,从而结束任务。如果您想跟踪挂起的执行,您必须自己跟踪这些执行并采取相应的行动。任务框架本身不提供终止任务的方法。您可以找出某个任务正在运行的线程并终止该线程,但这是一个肮脏的解决方案,不推荐这样做。