gpt4 book ai didi

c# - TaskCancellationException 如何避免成功控制流的异常?

转载 作者:太空狗 更新时间:2023-10-29 17:53:21 26 4
gpt4 key购买 nike

在我们的应用程序中,我们经常使用 async/await 和 Tasks。因此它确实经常使用 Task.Run,​​有时使用内置的 CancellationToken 取消支持。

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

如果我现在使用 CancellationToken 取消执行,执行会在下一个循环开始时停止,或者如果任务根本没有启动,它会抛出异常(Task.Run 中的 TaskCanceledException)。现在的问题是为什么 Task.Run 使用 Exception 来控制成功取消而不是仅仅返回一个完成的 Task。 MS 没有遵守“不要使用异常来控制执行流程”规则有什么具体原因吗?

我怎样才能避免在完全无用的 try catch (TaskCancelledException) block 中对支持取消(很多)的每个方法进行装箱?

最佳答案

好吧,在非常简单的场景中您真的看不出区别 - 您实际上并没有使用 Task 的结果,并且您不需要通过复杂的调用栈。

首先,您的 Task 可能会返回一个值。操作取消时返回什么?

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

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

最后,任务取消,就像线程中止一样,是一种异常(exception)情况。它已经涉及同步、堆栈展开等。

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

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!*)。

(*) 免责声明:我们实际上没有 cookie。但您可以自己制作!

关于c# - TaskCancellationException 如何避免成功控制流的异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34286303/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com