【问题标题】:Asynchronously abort C# TPL Tasks异步中止 C# TPL 任务
【发布时间】:2017-07-21 02:31:50
【问题描述】:

有没有办法异步中止使用 Task.Factory.Create(() => {stuff}); 创建的 C# TPL 任务?我已经看到有一种使用CancellationToken 的方法,但我喜欢避免使用IsCancellationRequested 进行检查。

【问题讨论】:

  • IsCancellationRequested 有什么问题?合作取消几乎肯定是您想要的。
  • 没办法,那是很刻意的。
  • 当你不知道它可能对任何共享状态做什么时,从另一个线程下拉出地毯是个坏主意

标签: c# task-parallel-library


【解决方案1】:

编辑:针对 .NET 4.5 和更新版本进行了更新,详细信息在帖子底部。


CancellationToken 是您想要使用的。检查IsCancellationRequested 可能看起来很痛苦,但它提供了一种处理取消的干净方法,而不是创建一个线程,然后中止它并且必须在并行运行的整个代码中处理线程中止异常。

var cts = new CancellationTokenSource();
var token = cts.Token;
var task = Task.Run(() =>
{
    // Do Job Step 1...
    if (token.IsCancellationRequested)
    {
        // Handle cancellation here, if necessary.

        // Thanks to @svick - this will set the Task status to Cancelled
        // by throwing OperationCanceledException inside it.
        token.ThrowIfCancellationRequested();
    }
    // Do Job Step 2...
    // ...
}, token);

// Later, to kill all the tasks and their children, simply:
cts.Cancel();

这可能会给委托增加一些混乱,但取消本身是如此简单,以至于我不需要使用任何比取消令牌源更粗略的东西。你还没有说你为什么要避免它,所以除非有一些硬性限制,否则我会坚持使用取消令牌。


根据@ipavlu 的评论,对于像这样的简单用例,最好使用Task.Run 而不是原来的Task.Factory.StartNew 来触发异步工作。它们提供相同的基本功能,但Task.Run 具有更安全的默认值和对更新的async 功能的更好支持,而Task.Factory.StartNew 可用于指定高级行为。更多信息例如在这里:https://blogs.msdn.microsoft.com/pfxteam/2011/10/24/task-run-vs-task-factory-startnew/

【讨论】:

  • 我认为通常最好使用ThrowIfCancellationRequested(),而不是检查IsCancellationRequested,以便将Task标记为Canceled
  • 使其使用默认调度程序。这样会导致死锁,如果这里的代码在 UI 上下文中继续运行,那么任务委托也将在 UI 上下文中运行,而不是在默认调度程序 ThreadPool 上运行。设置其他选项以防止子附加等是个好主意... Task.Run 实现显示使用 StartNew 的最佳方式...
  • @ipavlu:已更新。这是一篇相当老的帖子,但将它带到这个十年并没有什么坏处。
【解决方案2】:

取消可能难以实现,但这主要是因为取消与一般并行处理一样复杂。您几乎肯定不想允许在代码中的任意点中止,因为这会创建几乎与异步执行方法中的代码行一样多的新边界情况来测试。这是一种噩梦般的场景,会导致在野外发生几乎不可能重现的罕见崩溃。

设计异步流程的一部分是决定在哪里可以安全取消以及应该如何处理取消。这也可能意味着识别您进行的阻塞 API 调用(例如网络 I/O)并调用适当的方法来中断这些阻塞操作。适当地支持合作取消需要大量的前期设计工作,但是,如果需要该功能,前期投资将超过以后减少麻烦的回报。不过,这确实意味着您在为取消功能做预算时要保持保守,因为它很少像听起来那么简单。

【讨论】:

  • 如果您调用的库方法直接支持取消,那么支持取消会简单得多。因此,例如,对于网络 IO,从 WebClient 切换到 HttpClient 可能是有意义的。
猜你喜欢
  • 1970-01-01
  • 2020-09-08
  • 1970-01-01
  • 2017-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多