【问题标题】:How do I abort a .NET task?如何中止 .NET 任务?
【发布时间】:2011-08-13 20:21:42
【问题描述】:

情况是这样的,我正在编写代码战竞赛的框架。随着代码的运行,对于每一轮,它都会调用每个参赛者提供的库中的一个方法。比赛的规则是方法必须在 1 秒内返回,否则我们会杀死调用它们的任务。然后我们使用该回合的默认结果。

该方法不支持取消,因为我们不能相信被调用的代码会响应取消。而且我们需要终止线程,因为如果我们有 10 或 20 个被忽略的后台任务,那么所有向前的调用将为每次调用提供更少的时钟周期,而以前花费不到 1 秒的方法现在需要更多。

从好的方面来说,我们正在杀死的方法应该没有打开任何资源等,因此中止不应该留下任何悬而未决的东西。

更新:这里要记住两件事。首先,这就像一场游戏——所以性能很重要。其次,工作线程不太可能打开任何资源。如果调用的方法之一过长,我需要中止它并快速继续。

【问题讨论】:

  • 你不能杀死线程或任务(并期望保持稳定的应用程序)。
  • 我同意这是个坏主意。不幸的是,在现实世界中,有时我们必须在没有好的解决方案时实施最不坏的想法。对于这种情况,您有什么建议?
  • 标准答案是在单独的进程或 AppDomain 中启动代码。在这里询问并回答了许多计时器,我链接的骗子也不是最好的。
  • 约翰 - 我妈妈教我在请求帮助时说谢谢。我担心妈妈会否决一切,所以我在提问时会以感谢和我的名字签名。
  • 约翰 - 有趣的讨论。我绝对同意那里的少数人的观点,即谢谢你很好。由于不鼓励但不被禁止,我将继续这样做。

标签: c# .net task task-parallel-library abort


【解决方案1】:

您应该以低权限在每个参赛者自己的 AppDomain 中运行。这有几个优点:

  1. 它是沙盒的
  2. 它不能与进程中的任何其他代码交互
  3. 强制卸载 AppDomain 相对干净。

即使您更喜欢终止线程而不是卸载 AppDomain,我仍然会将每个参赛者放入 AppDomain 以实现隔离。

很遗憾,Thread.Abort 还不够。它仍然执行finally 子句,可以根据需要执行。

【讨论】:

  • 应用域是一个有趣的想法。如果出于性能原因超时,我仍然会中止而不是重新加载它。我不认为他们会有 finally 子句——问题不是他们会故意选择做坏事,只是他们的代码需要很长时间才能运行。谢谢
【解决方案2】:

我建议您在第二个进程中运行代码,并仔细定义与它通信的接口,以确保它可以处理不接收响应的情况。大多数操作系统的设计目的是在杀死进程后很好地进行清理。

对于通信,您可能应该避免使用 .NET 远程处理,因为这可能会在服务器端处于不一致的状态。其他一些选择:套接字、命名管道、Web 服务。

【讨论】:

  • “套接字、命名管道、Web 服务”- 使用 WCF。它(或多或少)是 .Net Remoting 的官方替代品,并支持所有这些绑定。
  • 这通常是最好的方法,像 Chrome 一样的沙盒。但是,我猜几乎不可能通过每次启动一个全新进程的开销来强制 1 秒超时。目标似乎是“最佳运行时间获胜”之类的东西,这在这里会出现问题。
  • 是的,这种情况下的开销会很大。
  • 您可以将其设计为仅在实际超过超时时才终止进程。这应该会减少单独进程的开销。
【解决方案3】:

Thread.Interrupt() 方法也许正是您要找的。​​p>

正如 MSDN 文档所说,“如果此线程当前未在等待、睡眠或加入状态下被阻塞,它将在下一次开始阻塞时被中断。”

不是abort,它强制运行线程在线程进入等待状态时抛出ThreadInterruptedException。

然后您可以在另一个线程中使用具有超时的计时器来检查线程是否真的不想终止,如果线程拒绝在例如 30 秒内终止,您可以中止它。

【讨论】:

  • 每次响应过长时,我都无法等待 30 秒。这可能会将 1 分钟的比赛变成数小时。我想我需要直接中止。
猜你喜欢
  • 1970-01-01
  • 2010-11-10
  • 1970-01-01
  • 2011-05-20
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多