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

我正在运行一个定期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 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 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请求应该消失,并生成否定结果。 我添加了取消令牌以尝试处理我的问题,如下所示。

我让它运行了很长时间 – 首先,一切运行良好,但最终(通过定期runTest()调用的数百次,如果不是更多次迭代)似乎其中一个任务被卡住并且未调用取消令牌,并且curl测试过程被有效地卡住了。

除了挑选哪些URL有问题(并且它们都是有效的),可以做些什么来诊断出现了什么问题? 或者我是否完全错误地构建了我的并行Curls? (我很欣赏我可以将新的Curls实例化为已经从上一轮完成的URL并让悬挂的一个悬挂,而不是在开始新批次之前等待它们全部完成,但我并不担心这个效率获得)。

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

以下行是您的问题:

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

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

您需要在任务执行期间定期检查取消令牌,以达到您的要求。