是否有取消异步任务的正确方法?

编程入门 行业动态 更新时间:2024-10-24 13:25:39
本文介绍了是否有取消异步任务的正确方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我遇到了一个如何正确取消异步任务的问题。

I encountered a problem how to properly cancel an asynchronous task.

这里是一些草稿。

我的入口点运行两个异步任务。第一个任务完成了一些长时间工作,第二个任务取消了它。

My entry point runs two asynchronous task. The first task does some 'long' work and the second one cancels it.

入口点:

private static void Main() { var ctc = new CancellationTokenSource(); var cancellable = ExecuteLongCancellableMethod(ctc.Token); var cancelationTask = Task.Run(() => { Thread.Sleep(2000); Console.WriteLine("[Before cancellation]"); ctc.Cancel(); }); try { Task.WaitAll(cancellable, cancelationTask); } catch (Exception e) { Console.WriteLine($"An exception occurred with type {e.GetType().Name}"); } }

返回可取消任务的方法:

private static Task ExecuteLongCancellableMethod(CancellationToken token) { return Task.Run(() => { token.ThrowIfCancellationRequested(); Console.WriteLine("1st"); Thread.Sleep(1000); Console.WriteLine("2nd"); Thread.Sleep(1000); Console.WriteLine("3rd"); Thread.Sleep(1000); Console.WriteLine("4th"); Thread.Sleep(1000); Console.WriteLine("[Completed]"); }, token); }

我的目的是停止写 1st, 2nd, 3rd取消后立即被调用。 但是我得到以下结果:

My purpose is to stop writing '1st','2nd','3rd' immediately after cancellation is called. But I get following results:

1st 2nd 3rd [Before cancellation] 4th [Completed]

出于明显的原因请求取消时,我没有抛出异常。因此,我尝试将方法重写如下:

For obvious reason I didn't get an exception that throws when cancellation is requested. So I tried to rewrite method as following:

private static Task ExecuteLongCancellableAdvancedMethod(CancellationToken token) { return Task.Run(() => { var actions = new List<Action> { () => Console.WriteLine("1st"), () => Console.WriteLine("2nd"), () => Console.WriteLine("3rd"), () => Console.WriteLine("4th"), () => Console.WriteLine("[Completed]") }; foreach (var action in actions) { token.ThrowIfCancellationRequested(); action.Invoke(); Thread.Sleep(1000); } }, token); }

现在我得到了想要的东西:

And now I got what I want:

1st 2nd [Before cancellation] 3rd An exception occurred with type AggregateException

但是我想创建一个Action委托集合并遍历它并不是解决我的问题的最方便方法。

But I guess creating of a collection of Action delegates and looping through it is not the most convenient way to deal with my problem.

那么正确的方法是什么?为什么我需要将取消令牌作为第二个参数传递给Task.Run方法?

推荐答案

任务不会取消其自身,您有责任检测取消请求并彻底中止工作。这就是 token.ThrowIfCancellationRequested(); 的作用。

The Task won't cancel its self, it is up you you to detect the cancellation request and cleanly abort your work. That's what token.ThrowIfCancellationRequested(); does.

您应该将这些检查放在整个代码中,放在可以完全停止执行,也可以将执行回滚到安全状态。

You should place those checks throughout your code, in places where execution can be cleanly stopped, or rolled back to a safe state.

在第二个示例中,您在循环的每次迭代中都调用它一次,并且效果很好。第一个示例从一开始就只调用一次。如果到那时还没有取消令牌,则任务将完成,就像您看到的一样。

In your second example, you call it once per iteration of the loop, and it works fine. The first example only calls it once, at the very start. If the token hasn't been canceled by that point, the task will run to completion, just like you are seeing.

如果将其更改为如下所示,您将还会看到您期望的结果。

If you changed it to look like this, you would also see the results you expect.

return Task.Run(() => { token.ThrowIfCancellationRequested(); Console.WriteLine("1st"); Thread.Sleep(1000); token.ThrowIfCancellationRequested(); Console.WriteLine("2nd"); Thread.Sleep(1000); token.ThrowIfCancellationRequested(); Console.WriteLine("3rd"); Thread.Sleep(1000); token.ThrowIfCancellationRequested(); Console.WriteLine("4th"); Thread.Sleep(1000); Console.WriteLine("[Completed]"); }, token);

更多推荐

是否有取消异步任务的正确方法?

本文发布于:2023-11-08 06:59:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1568663.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:正确   方法

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!