寻找编写需要一个接一个地运行异步的函数链的最佳方法。鉴于这两个选项:
选项1
def operation1(): Unit = {...}
def operation2(): Unit = {...}
def foo(): Future[Unit] =
Future {
operation1()
operation2()
} onComplete {case _ => println("done!")}
选项2
def operation1(): Future[Unit] = {...}
def operation2(): Future[Unit] = {...}
def foo(): Future[Unit] = {
operation1()
.flatMap {case _ => operation2() }
.onComplete {case _ => println("done!")}
}
另一个问题,鉴于此功能:
def foo: Future[A]
如果我想将结果转换为单位,这是最好的方法:
foo map { _ => () }
谢谢!
答案 0 :(得分:3)
选项1 优于选项2 的潜在优势在于,它保证operation2
将在operation1
后立即运行 - 如果它没有&# 39; t因异常而失败 - 而在选项2 中,当flatMap
完成时,您可能已经耗尽了线程池可用线程。
是的, Option1 肯定会在同一个线程中运行操作。 选项2 会尝试在两个线程中运行它们,只要有足够的可用空间。
flatMap[S](f: (T) ⇒ Future[S])(implicit executor: ExecutionContext): Future[S]
您必须声明一个隐式执行上下文,或者导入它:它确定您正在使用哪个池。如果您导入了默认的global
执行程序,那么您的池是一个基于fork的连接,默认情况下 - 与您加工的内核一样多的线程。
第一个选项就像让一个线程同时运行两个操作,而第二个选项在一个线程中运行第一个操作,然后尝试从ExecutionContext获取另一个线程来运行第二个操作。 /强>
最佳做法是使用您需要的东西:
您是否要确保operation2
在执行上下文中没有更多线程可用的上下文中运行?如果答案为是,则使用 Option1 < / strong>即可。否则,您可以使用 Option2
关于您的上一个问题:您在提议的代码段中执行的操作不是强制转换,您正在映射一个函数,该函数为Unit
类型的任何值提供A
值。结果是你得到了Unit
类型的未来,这对于检查其完成状态很有用。这是获得你想要的东西的最好方法。
然而,请注意,与flatMap
一样,执行该&#34;转换功能&#34;将在您的上下文中的隐式执行程序提供的不同线程中运行。这就是map
也有隐含参数executor
的原因:
def map[S](f: (T) ⇒ S)(implicit executor: ExecutionContext): Future[S]