c# - 为什么我的任务没有取消?

标签 c# task libcurl

我正在运行一个进程,该进程会定期 curl 到 URL 列表以测试这些网站的性能。我的主程序基本上是一个 do...sleep...while 循环,每 N 秒调用一个函数 runTest(),并通过键盘中断将其终止。归根结底,我的代码如下:

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”函数按照它在 jar 上所说的那样进行操作,将 http 超时值设置为取消 token 的一半,以便 HTTP 请求在调用取消 token 之前消失,并生成否定结果。我添加了取消 token 来尝试处理我的问题,如下所示。

我让这个运行了很长时间——开始时,一切正常,但最终(数百次,如果不是通过周期性 runTest() 调用的更多迭代)似乎其中一个任务被卡住了,取消 token 是' t被调用,curl测试过程有效卡住。

除了找出哪些 URL 有问题(而且它们都是有效的 URL)之外,还可以做些什么来诊断出了什么问题?或者我一开始就完全错误地构建了我的平行 curl ? (我很欣赏我可以将新的 Curls 实例化到上一轮完成的 URLs 并让挂起的 URLs 悬空,而不是在开始新的批处理之前等待它们全部完成,但我并不担心这种效率增益)。

最佳答案

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

下一行是你的问题:

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

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

您需要在任务执行期间定期检查您的取消 token 以实现您想要的。

关于c# - 为什么我的任务没有取消?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40766222/

相关文章:

django - 使用 django 和 celery 运行周期性任务

ruby-on-rails - 如何解决 'libcurl' not found with Rails on Windows

c# - Mono.Cecil:操作可能会在运行时不稳定

c# - 带 Moq 的 MV3 测试项目,使用特定表达式时如何返回对象?

c# - 无法在 XNA 中将 Awesomium 渲染到屏幕上

c# - 将日期范围拆分为日期范围 block

concurrency - D taskpool 等到所有任务完成

c# - .Net Async ContinueWith VS 在任务中嵌入任务

c - 使用 libcurl 检索到的 header 信息来确定文件名

c++ - 如何使用带有 libcurl 的 HTTP 在 C/C++ 中上传文件?