使用 CancellationToken 取消任务而不显式检查任务?

sch*_*227 4 c# task cancellation

背景:

我有一个 Web 应用程序,它启动长时间运行(和无状态)的任务:

var task = Task.Run(() => await DoWork(foo))

task.Wait();
Run Code Online (Sandbox Code Playgroud)

因为它们长时间运行,我需要能够从单独的 Web 请求中取消它们。

为此,我想使用 CancellationToken 并在取消令牌后立即抛出异常。但是,从我读过的内容来看,任务取消是合作的,这意味着任务正在运行的代码必须显式检查令牌以查看是否已发出取消请求(例如CancellationToken.ThrowIfCancellation()

我想避免CancellationToken.ThrowIfCancellation()到处检查,因为任务很长并且要经过许多功能。我想我可以完成我想要创建的显式Thread,但我真的很想避免手动线程管理。那说...

问题: 是否有可能在任务被取消时自动在任务中抛出异常,如果没有,是否有任何好的替代方案(模式等)来减少对代码的污染CancellationToken.ThrowIfCancellation()

我想避免这样的事情:

async Task<Bar> DoWork(Foo foo)
{
    CancellationToken.ThrowIfCancellation()

    await DoStuff1();

    CancellationToken.ThrowIfCancellation()

    await DoStuff2();

    CancellationToken.ThrowIfCancellation()

    await DoStuff3();
...
}
Run Code Online (Sandbox Code Playgroud)

我觉得这个问题是来自不同足够这一个,因为我明确要求的方式,以尽量减少通话检查取消标记,对此接受的回答,“每一个现在,然后,该函数中,调用token.ThrowIfCancellationRequested( )”

Ste*_*ary 5

是否可以在任务被取消时自动在任务中抛出异常,如果没有,是否有任何好的替代方案(模式等)来减少 CancellationToken.ThrowIfCancellation() 对代码的污染?

不,也没有。所有取消都是合作的。取消代码的最佳方法是让代码响应取消请求。这是唯一好的模式。

我想我可以完成我想要创建的显式线程

并不真地。

此时,问题是“如何取消不可取消的代码?” 答案取决于您希望系统的稳定性:

  1. 运行在一个独立的代码ThreadAbort线程,当它不再是必要的。这是最容易实现的,但在应用程序不稳定方面最危险。坦率地说,如果你曾经Abort在你的应用程序中的任何地方调用过,你应该定期重启该应用程序,除了像心跳/烟雾测试这样的标准做法。
  2. 运行在一个独立的代码AppDomainUnload该AppDomain中时,它不再是必要的。这更难实现(您必须使用远程处理),并且在 Core 世界中不是一个选项。事实证明,AppDomains 甚至不能像预期的那样保护包含的应用程序,因此任何使用此技术的应用程序也需要定期重新启动。
  3. 运行在一个独立的代码ProcessKill进程时就不再需要。这是实现起来最复杂的,因为您还需要实现某种形式的进程间通信。但它是取消不可取消代码的唯一可靠解决方案

如果你丢弃不稳定的解决方案 (1) 和 (2),那么唯一剩下的解决方案 (3) 是大量的工作 - 方式,不仅仅是使代码可取消。

TL;DR:只需按照设计使用的方式使用取消 API。这是最简单、最有效的解决方案。

  • 我想知道你是否愿意插话,克利里先生。你提出的观点与我一直在研究的内容相符,但我需要的是对实现这些观点的难度/不稳定性的洞察。阅读您的其他帖子,我学到了很多东西,非常感谢您的意见。 (2认同)