为什么我的任务没有取消?
Why does my task not cancel?
我是 运行 一个定期卷曲到 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" 函数按照它在罐子上所说的那样做,将 http 超时值设置为取消令牌的一半,以便 HTTP 请求在取消令牌被调用之前消失,并生成一个阴性结果。我添加了取消令牌来尝试处理我的问题,如下所示。
我将此 运行 保留了很长时间 - 首先,一切正常,但最终(数百次,如果不是通过定期 runTest() 调用的更多迭代)似乎其中一项任务卡住了并且没有调用取消令牌,并且 curl 测试过程有效地卡住了。
除了找出哪些 URL(s) 有问题(而且它们都是有效的)之外,还可以做些什么来诊断出了什么问题?或者我一开始就完全错误地构建了我的平行卷曲? (我很感激我可以将新的 Curls 实例化到 URLs 已经从上一轮完成并让挂起的人悬空,而不是在开始新的批次之前等待它们全部完成,但我不关心效率的提高)。
取消没有自动性。您必须检查取消状态并结束执行或调用 CancellationToken.ThrowIfCancellationRequested
来执行取消。 CancellationToken
会告诉您 如果 请求取消;取消 本身 必须由您完成。
下一行是你的问题:
Task t = new Task(() => easy.Perform(), cts.Token);
您正在将令牌传递给任务构造函数。如果您在任务开始 之前 取消,这将对您有所帮助。一旦任务开始,执行的方法负责取消。 easy.Perform()
不知道您的取消令牌,因此永远无法确定是否请求取消。因此,它将运行结束。
您需要在任务执行期间定期检查您的取消令牌以实现您想要的。
我是 运行 一个定期卷曲到 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" 函数按照它在罐子上所说的那样做,将 http 超时值设置为取消令牌的一半,以便 HTTP 请求在取消令牌被调用之前消失,并生成一个阴性结果。我添加了取消令牌来尝试处理我的问题,如下所示。
我将此 运行 保留了很长时间 - 首先,一切正常,但最终(数百次,如果不是通过定期 runTest() 调用的更多迭代)似乎其中一项任务卡住了并且没有调用取消令牌,并且 curl 测试过程有效地卡住了。
除了找出哪些 URL(s) 有问题(而且它们都是有效的)之外,还可以做些什么来诊断出了什么问题?或者我一开始就完全错误地构建了我的平行卷曲? (我很感激我可以将新的 Curls 实例化到 URLs 已经从上一轮完成并让挂起的人悬空,而不是在开始新的批次之前等待它们全部完成,但我不关心效率的提高)。
取消没有自动性。您必须检查取消状态并结束执行或调用 CancellationToken.ThrowIfCancellationRequested
来执行取消。 CancellationToken
会告诉您 如果 请求取消;取消 本身 必须由您完成。
下一行是你的问题:
Task t = new Task(() => easy.Perform(), cts.Token);
您正在将令牌传递给任务构造函数。如果您在任务开始 之前 取消,这将对您有所帮助。一旦任务开始,执行的方法负责取消。 easy.Perform()
不知道您的取消令牌,因此永远无法确定是否请求取消。因此,它将运行结束。
您需要在任务执行期间定期检查您的取消令牌以实现您想要的。