TaskCancellationException如何避免成功控制流程上的异常? [英] TaskCancellationException how to avoid the exception on success control flow?

查看:441
本文介绍了TaskCancellationException如何避免成功控制流程上的异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我们的应用程序中,我们使用async / await和Tasks进行了大量工作。因此它确实使用Task。运行很多,有时使用内置的 CancellationToken 具有取消支持。

In our application we work a lot with async / await and Tasks. Therefore it does use Task.Run a lot, sometimes with cancellation support using the built in CancellationToken.

public Task DoSomethingAsync(CancellationToken cancellationToken)
{
    return Task.Run(() =>
    {
        while (true)
        {
            if (cancellationToken.IsCancellationRequested) break;
            //do some work
        }
    }, cancellationToken);
}

如果我现在使用CancellationToken取消执行,则执行会停止在下一个循环的开始,或者如果Task根本没有启动,它将引发异常(Task.Run中的TaskCanceledException)。现在的问题是,为什么Task.Run使用Exception来控制成功的取消,而不是仅仅返回完成的Task。 MS是否不遵循请勿使用异常来控制执行流程规则的任何特定原因??

If i do now cancel the execution using the CancellationToken the execution does stop at the beginning of the next loop, or if the Task did not start at all it throws an exception (TaskCanceledException inside Task.Run). The question is now why does Task.Run use an Exception to control successful cancellation instead of just returning a completed Task. Is there any specific reason MS did not stick to the "Do NOT use exceptions to control execution flow" rule?.

我如何避免将支持取消的每种方法装箱(很多)完全没有用的try catch(TaskCancelledException)块中?

And how can i avoid Boxing every method that supports cancellation (which are a lot) in an completely useless try catch (TaskCancelledException) block?

推荐答案

在非常简单的情况下,您真的看不到差异-您实际上并没有使用 Task ,您无需通过复杂的调用堆栈传播取消信息。

Well, you can't really see the difference in your very simple scenario - you're not actually using the result of the Task, and you don't need to propagate the cancellation through a complex call stack.

首先,您的任务可能返回一个值。取消操作后,您返回什么?

First, your Task might return a value. What do you return when the operation was cancelled?

第二,取消的任务之后可能还有其他任务。您可能希望在方便时通过其他任务传播取消信息。

Second, there may be other tasks that follow your cancelled task. You probably want to propagate the cancellation through the other tasks at your convenience.

异常传播。在这种用法中,任务取消与 Thread.Abort 几乎相同-当您发出 Thread.Abort 时, ThreadAbortException 用于确保您完全退回到顶部。否则,您的所有方法都必须检查它们调用的每个方法的结果,检查它们是否已取消,并在需要时返回自己-我们已经看到人们会忽略老式C中的错误返回值:)

Exceptions propagate. Task cancellation is pretty much identical to Thread.Abort in this usage - when you issue a Thread.Abort, a ThreadAbortException is used to make sure you unwind all the way back to the top. Otherwise, all of your methods would have to check the result of every method they call, check if they were cancelled, and return themselves if needed - and we've already seen that people will ignore error return values in old-school C :)

最后,就像线程中止一样,任务取消是一种例外情况。它已经涉及到同步,堆栈展开等。

In the end, task cancellation, just like thread aborts, is an exceptional scenario. It already involves synchronization, stack unwinding etc.

但是,这并不意味着您必须使用 try-catch 捕获异常-您可以使用任务状态。例如,您可以使用如下帮助函数:

However, this doesn't mean you necessarily have to use try-catch to catch the exception - you can use task states. For example, you can use a helper function like this:

public static Task<T> DefaultIfCanceled<T>(this Task<T> @this, T defaultValue = default(T))
{
  return
    @this.ContinueWith
      (
        t =>
        {
          if (t.IsCanceled) return defaultValue;

          return t.Result;
        }
      );
}

可以用作

await SomeAsync().DefaultIfCanceled();

当然,应该注意,noöne强迫您使用这种取消方法-这很简单为方便起见。例如,您可以使用自己的放大类型来保存取消信息,并手动处理取消。但是,当您开始执行此操作时,您会发现使用异常处理取消的原因-在命令式代码中执行此操作很痛苦,因此您要么浪费很多精力就没有收获,要么切换到更多功能的编程方式(来吧,我们有cookie!*。)。

Of course, it should be noted that noöne is forcing you to use this method of cancellation - it's simply provided as a convenience. For example, you could use your own amplified type to preserve the cancellation information, and handle the cancellation manually. But when you start doing that, you'll find the reason why cancellation is handled using exceptions - doing this in imperative code is a pain, so you'll either waste a lot of effort for no gain, or you'll switch to a more functional way of programming (come, we have cookies!*).

(*)免责声明:我们实际上没有cookie。但是你可以自己做!

这篇关于TaskCancellationException如何避免成功控制流程上的异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆