繁体   English   中英

Scala 期货和 `andThen` 异常传播

[英]Scala futures and `andThen` exception propagation

我正在阅读 scala.concurrent.Future 模块中andThen函数的 Scala 2.11.8 文档,它说如下:

def andThen[U](pf: PartialFunction[Try[T], U])
              (implicit executor: ExecutionContext): Future[T]

将副作用函数应用于此未来的结果,并使用此未来的结果返回一个新的未来。

此方法允许强制以指定的顺序执行回调。

请注意,如果链接的 andThen 回调之一抛出异常,则该异常不会传播到后续的 andThen 回调。 相反,随后的 andThen 回调被赋予这个未来的原始值。

我不确定andThen不传播异常到底是什么意思,也没有提供示例。 例如,如果我做这样的事情:

Future.successful { throw new RuntimeException("test") } andThen
                  { case _ => println("test") }

在 Scala REPL 中,我得到:

java.lang.RuntimeException: test
  ... 32 elided

所以这个异常被传播了。 有人可以提供一个有意义的例子,这究竟意味着什么,以及使用andThen和我想从中恢复的抛出异常的代码是否安全。 谢谢。

不要在Future.successful {} throw异常。

这是正确的方法

Future { throw new RuntimeException("test") } andThen
                  { case _ => println("test") }

你可以通过下面这行代码来理解andThen的用法

Future.successful { 1 } andThen { case _ =>  "foo" }

复制代码

@ Future.successful { 1 } andThen { case _ =>  "foo" }
res7: Future[Int] = Success(1)

复制代码

@ Future.successful { 1 } andThen { case _ =>  println("foo") }
foo
res8: Future[Int] = Success(1)

复制代码

@ val result = Future.successful { 1 } andThen { case _ =>  "foo" }
result: Future[Int] = Success(1)

在上面的例子中

我们可以看到执行了 andthen 之后的部分函数,​​但忽略了部分函数的返回类型。 最后结果输出是Future结果,它是Future[Int]

这意味着addThen用于在Future完成后立即执行副作用函数。

当未来失败时

复制代码

@ val result = Future { throw new Exception("bar") } andThen { case _ =>  "foo" }
result: Future[Nothing] = Failure(java.lang.Exception: bar)

复制代码

@ val result = Future { throw new Exception("bar") } andThen { case _ =>  println("foo") }
foo
result: Future[Nothing] = Failure(java.lang.Exception: bar)

当 future 失败时也是如此。 andThen之后的代码执行and但是andThen之后的代码的结果被忽略,最终结果是Future结果。

So andThen用于在 Future 完成后立即运行副作用代码。 andThen也将最终输出保留为Future的输出。

这就是andThen在标准库中的实现方式。

andThen驻留在Future类中

 def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = {
    val p = Promise[T]()
    onComplete {
      case r => try pf.applyOrElse[Try[T], Any](r, Predef.conforms[Try[T]]) finally p complete r
    }
    p.future
  }

1) 对这个future的结果应用副作用函数,并用这个future的结果返回一个新的future。

是的

pf是副作用代码,因为它的输出类型没有被使用(不能被使用)。 p.future是他所说的新未来。 Promise以之前的Future结果完成(看上面addThen的实现)

在 finally 块p complete r表示使用p.future创建新的 Future 并使用p.future Future 结果完成r

2) 此方法允许强制以指定的顺序执行回调。

是的。 您可以使用多个andThen调用链接多个回调,并且这些回调按照andThen调用的顺序依次执行。 这与onComplete方法相比,您可以多次使用它来注册多个回调,但这些回调的顺序是不确定的。

3) 请注意,如果链接的 andThen 回调之一抛出异常,则该异常不会传播到后续的 andThen 回调。 相反,随后的 andThen 回调被赋予这个未来的原始值。

是的

r是前一个未来的结果被赋予pf (看上面的 andThen 代码)

我认为类型签名是最好的文档。 如您所见, andThen接受T => U (为简单起见省略了 PF 和 Try),并返回Future[T] 所以你可以想一想, andThen执行一些效果并返回原来的未来。 因此,如果您的部分函数andThen异常,它不会传播到其他andThen s,它们将作用于原始未来:

  import scala.concurrent.ExecutionContext.Implicits.global
  Future{ 2 } andThen {
    case _ => throw new RuntimeException("test")
  } andThen {
    case v ⇒ println("After exception"); println(v)
  }
Thread.sleep(500)

这打印:

java.lang.RuntimeException: test    
After exception
Success(2)

附注。 再次通读您的示例。 我想你只是最后忘记了 Thread.sleep 以便在程序结束之前完成未来。 所以你可能正确理解了一切。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM