为什么我的任务没有取消? [英] Why does my task not cancel?

查看:42
本文介绍了为什么我的任务没有取消?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在运行一个过程,该过程会定期卷曲到URL列表以测试这些网站的性能.我的主程序基本上是一个do ... sleep ... while循环,每N秒调用一次函数runTest(),并通过键盘中断将其杀死.简而言之,我的代码如下:

I'm running a process that periodically Curls to a list of URLs to test out performance to those websites. My main program is basically a do...sleep...while loop that calls a function, runTest() every N seconds, with a keyboard interrupt to kill it off. Pared down to the basics, my code is as follows:

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"函数按照提示进行操作,将http超时值设置为取消令牌的一半,以便HTTP请求在取消令牌被调用之前就消失,并产生否定的结果.我添加了取消令牌,以尝试解决以下问题.

The "doAsyncCurl" function does what it says on the tin, setting an http timeout value to half that of the cancellation token, so that the HTTP request should evaporate before the cancellation token is invoked, and generate a negative result. I added the cancellation token to try and deal with my problem as below.

我花了很长时间才开始-一切正常,但最终(数百次,如果通过定期runTest()调用进行了更多次迭代),似乎其中一项任务被卡住了,而取消标记是调用t,从而有效地阻止了卷曲测试过程.

I leave this running for ages - to start with, everything works well, but eventually (hundreds, if not more iterations through the periodic runTest() invocation) it seems that one of the tasks gets stuck and the cancellation token isn't invoked, and the curl testing process is effectively stuck.

除了挑选出有问题的URL(它们都是有效的URL)之外,还能做些什么来诊断出什么问题了?还是我一开始就完全错误地构建了并行Curls? (我很欣赏我可以将新的Curls实例化到上一轮结束的URL,而让挂起的URL悬空,而不是等到它们全部完成之后再开始新的批处理,但是我对此效率并不感到困扰.增益).

Apart from picking up which URL(s) are problematic (and they're all valid ones), what can be done to diagnose what's going wrong? Or have I constructed my parallel Curls completely wrongly to start with? (I appreciate that I could instantiate new Curls to URLs that have finished from the previous round and leave the hung one to dangle, rather than waiting for them all to finish before kicking off a new batch, but I'm not bothered about that efficiency gain).

推荐答案

取消中没有自动机制.您必须检查取消状态并结束执行,或调用CancellationToken.ThrowIfCancellationRequested来执行取消. CancellationToken会告诉您是否请求取消;取消本身必须由您完成.

There is no automatism in cancellation. You have to check for the cancellation status and end your execution or invoke CancellationToken.ThrowIfCancellationRequested to perform the cancellation. The CancellationToken will tell you if cancellation is requested; the cancellation itself has to be done by you.

以下一行是您的问题:

Task t = new Task(() => easy.Perform(), cts.Token);

您正在将令牌传递给任务构造函数.如果您在任务开始前 取消操作,这将对您有所帮助.一旦任务开始,执行的方法将负责取消. easy.Perform()不知道您的取消令牌,因此将永远无法确定是否请求取消.因此,它将运行到尽头.

You are passing the token to the task constructor. That will help you if your cancellation occurs before the task is started. Once the task is started, the executed method is responsible for cancellation. easy.Perform() does not know about your cancellation token and therefore will never be able to determine if cancellation is requested. Hence, it will run to its end.

您需要在任务执行期间定期检查取消令牌,以实现所需的目标.

You need to regularly check your cancellation token during task execution to achieve what you want.

这篇关于为什么我的任务没有取消?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆