Future何时可以返回未在Future体内抛出的异常?

时间:2015-05-01 01:36:00

标签: scala concurrency future

这里更一般的问题是:在生产质量代码中,是否需要关注ExecutionContext或其他并发基础架构产生的异常,而不是未来主体的执行?例如,如果线程池发生某些故障,我会在未来看到由于它而无法执行的异常吗?

反过来,这导致了如何使用期货进行错误处理。我正在使用一般建议,即应该使用例如错误返回错误,而不是抛出错误。无论是要么是scalactic的,要么是。但是,如果在调用未来时,需要考虑基础结构中的异常,即使其他所有内容都以无异常或异常包装的方式编写,这似乎也非常复杂。但我不会就此提出建议 - 我认为这个帖子会因为“过于宽泛”而被关闭。 :=(

2 个答案:

答案 0 :(得分:4)

如果在执行Future时发生异常但未在其中发生异常,我认为它不可能在Future内返回。 Future.apply的实现向执行者提交PromiseCompletingRunnable。它看起来像这样:

class PromiseCompletingRunnable[T](body: => T) extends Runnable {
  val promise = new Promise.DefaultPromise[T]()

  override def run() = {
    promise complete {
      try Success(body) catch { case NonFatal(e) => Failure(e) }
    }
  }
}

请注意,使用执行Promise主体的try / catch块完成了基础Future.apply。如果在上面的Runnable(似乎不太可能)或者try / catch块之外的执行程序中发生异常,它将不会包含在返回的Future中。如果在执行程序中发生某些异常,则更可能的情况是它有一些致命的错误。更糟糕的是,这可能意味着Future永远不会完成。

如果它是导致问题的线程池,除了找到更好的问题或识别潜在问题(线程太多?)之外,你真的无法做很多事情。 。而且在运行时你可以做的更少(如果有的话)。实际上,这只是意味着底层并发API非常破碎,使用了太多内存等等。

答案 1 :(得分:3)

是和否......好吧也许我们需要详细说明。

如果我们谈论“生产质量代码”,即如果代码无法运行则需要花费大量资金,我们无法假设基础设施(运行时,库等)正常工作。因为他们没有。库存有错误,即使它们不影响我们,它们依赖于有限的资源,如内存,文件句柄以及并发内容:线程。

因此,在某些方面应该意识到的一件事是:即使是最微不足道的代码行也可能失败。这就是Yes部分:是的,你应该关注这种可能性。

No部分旁边:你写

  

错误应该返回,而不是抛出,使用例如无论是要么是scalactic的还是

对于您期望的异常,情况确实如此。事情真的很可能会失败。比如在10万次执行中超过1次。 (是的,我把那个号码从我的帽子里拿出来,我甚至都不戴)。在这种情况下,添加显式异常处理是适当的事情,并且您提到的建议适用。

但它不适用于所有其他可能的故障模式。如果您尝试使用此方法处理它们,您将无法在所有异常处理之间找到主代码。你可能会在这个过程中添加许多错误。

相反,有一些一般策略如何处理代码中的任意异常。对于这些情况,例外是正确的工具。对于这种策略越简单越好,因为你真的不知道在什么样的情况下这个代码会被执行。

Web应用程序中的典型方法是在完整请求周围尝试catch块,记录异常并返回一些错误页面。

更精细的方法是像Akka这样的演员框架,它有Actors来完成工作。如果这样的Actor抛出异常,则Actor将死亡并被新的替换(用各种方式来控制确切的行为)。

另一种与上述两种方法相结合的方法是让应用程序的多个实例在不同的机器上运行,因此一台机器上的问题不会影响其他机器。

正如您所看到的,处理基础架构内部异常的方法(包括但不限于执行期货的库)与用于处理期货“正常”故障模式的异常处理非常不同。