当 Task.IsCancelled 设置为 true 时?

Posted

技术标签:

【中文标题】当 Task.IsCancelled 设置为 true 时?【英文标题】:when Task.IsCancelled is set as true? 【发布时间】:2017-06-28 17:50:07 【问题描述】:

什么时候来Task.IsCanceled = true;

代码:

var cts = new CancellationTokenSource();
string result = "";
cts.CancelAfter(10000);
try

    Task t = Task.Run(() =>
    
        using (var stream = new WebClient().OpenRead("http://www.rediffmail.com"))
        
            result = "success!";
        
        cts.Token.ThrowIfCancellationRequested();
    , cts.Token);
    
    Stopwatch timer = new Stopwatch();
    timer.Start();
    while (timer.IsRunning)
    
        if (timer.ElapsedMilliseconds <= 10000)
        
            if (result != "")                                                                                      
                timer.Stop();
                Console.WriteLine(result);
            
        
        else
        
            timer.Stop();
            //cts.Cancel();
            //cts.Token.ThrowIfCancellationRequested();
        
    

catch (OperationCanceledException)

    Console.WriteLine(t.IsCanceled); // still its appear in false.

我的要求是 - 任务在 10 秒内未完成,需要取消任务。

所以我正在设置计时器并观看给定的秒数。它未完成意味着取消任务并显示错误消息。

【问题讨论】:

请附上Minimal, Complete, and Verifiable example。您显示的内容不完整。 取消token还不够,需要查看method取消作业的代码 你能显示等待任务 t 的代码吗?正确地说,如果方法运行时间超过 20 秒,您想取消整个操作,是吗? 我将在哪里共享代码。这里无法分享代码。显示时间过长 【参考方案1】:

您必须将令牌传递给您的方法。它应该检查令牌并尊重对CancellationTokenSourceCancel() 的调用。

或者你自己做:

Task t = Task.Factory.StartNew(() =>

    myResult = method();  // Request processing in parallel

    cts.Token.ThrowIfCancellationRequested(); // React on cancellation 
, cts.Token);

一个完整的例子是这样的:

async Task Main()

    var cts = new CancellationTokenSource();
    var ct = cts.Token;
    cts.CancelAfter(500);

    Task t = null;
    try
    
        t = Task.Run(() =>  Thread.Sleep(1000); ct.ThrowIfCancellationRequested(); , ct);
        await t;
        Console.WriteLine(t.IsCanceled);
    
    catch (OperationCanceledException)
    
        Console.WriteLine(t.IsCanceled);
    

输出是一个OperationCanceledException被抛出,结果是

是的

如果您删除 ct.ThrowIfCancellationRequested(); 部分,它将显示

错误

编辑:

现在,您已经更新了问题,一些 cmets 对此进行了更新。首先,您将不再需要计时器,因为您使用的是CancelAfter 方法。其次,你需要await你的任务。所以这就是这样的:

string result = "";
cts.CancelAfter(10000);
Task t = null;
try

    t = Task.Run(() =>
    
        using (var stream = new WebClient().OpenRead("http://www.rediffmail.com"))
        
            cts.Token.ThrowIfCancellationRequested();
            result = "success!";
        
    , cts.Token);

    await t;

catch (OperationCanceledException)

    Console.WriteLine(t.IsCanceled); 

这应该表明t.IsCanceledtrue 但当然只有当WebClient 的调用需要超过10 秒时。

【讨论】:

Task t = Task.Factory.StartNew(() => myResult = method(); // 请求并行处理 , cts.Token); // 一段时间后 cts.cancel cts.Token.ThrowIfCancellationRequested();有可能吗?这里 t.iscancelled 永远不会出现 true。 你能显示等待任务 t 的代码吗?正确地说,如果方法运行时间超过 20 秒,您想取消整个操作,是吗? 如何分享代码?这里出现了太长的字符。 编辑或添加到您的问题中,这是最好的方法。 它不工作。 Web 客户端需要 10 秒。但它仍然没有来进行捕获操作。获得结果后,由于等待操作,只会返回结果。没有等待它可能吗?【参考方案2】:

来自文档:

在以下任一条件下,任务将在 TaskStatus.Canceled 状态下完成:

    它的 CancellationToken 在任务开始执行之前被标记为取消。

    任务通过抛出带有相同 CancellationToken 的 OperationCanceledException 来确认其已发出信号的 CancellationToken 的取消请求。

    任务通过调用 CancellationToken 上的 ThrowIfCancellationRequested 方法,在其已发出信号的 CancellationToken 上确认取消请求。

所以基本上你需要在你的任务中抛出一个OperationCanceledException来强制状态,例如在你取消它之后执行cts.Token.ThrowIfCancellationRequested()

但是这种机制的意图有点相反。您取消源说,当用户按下表单上的取消按钮(从您的任务之外)时,任务只是验证是否在某些安全的情况下请求取消以取消其代码的点。

【讨论】:

以上是关于当 Task.IsCancelled 设置为 true 时?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 id 设置为从 JSON 响应生成的 <tr>?

VUE 监听局部滚动 设置ICON的位置跟随

关于html中table表格tr,td的高度和宽度

js中怎样设置动态tr的属性

为啥 :hover 不适用于 tr 元素?

Hangfire循环任务20分钟后停止,是啥原因