未来和收益语法异步或同步?

时间:2018-07-04 02:02:46

标签: scala

我已经使用Scala相当一段时间了,我绊脚石 一个关于未来对收益理解的用法的非常重要的问题。

for-yield语法只是一种语法糖,它简化了flatMap / map链。期货应该是异步的包装器,但是flatMap / map的使用似乎起了更同步的作用,因为它似乎“等待”要计算的上一个Future调用的结果,因此可以对其进行操作。因此,这突然变得更加混乱,使我回到这个基本问题。期货是异步的,但是即使地图/平面图(收益率)的使用也允许它在收益率中进行顺序操作,它的使用也会异步吗?

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

map/flatMapfor表达式都用于将未来转换为另一个未来,并且它们是异步

对于map/flatMap

val future1 = Future {Thread.sleep(10000); 12}
val newFuture = future.map(res => res + 10)

在上面的代码块中,future1转换为newFuture,并且似乎是同步的,因为res + 10仅在future1完成后才计算,并且必须等待10 future1完成的秒数,然后计算总和并将此计算作为新的未来返回。但是,该动作是完全异步的,因为它们将在不同的上下文中执行,即future1newFuture将在不同的上下文中执行并且不会互相阻塞,但是newFuture期望future1成功完成并返回值12以执行res + sum,这使它看起来像同步过程,但从技术上讲却不是。

类似地,对于for expression

val future1 = Future {Thread.sleep(10000); 10}
val future2 = Future {Thread.sleep(15000); 20}
val newFuture = for {
    res1 <- future1
    res2 <- future2
} yield res1+res2

在上述情况下,future1future2在不同的上下文中并行执行,当所有将来完成时,它们最终将产生总和-res1 + res2future1需要10秒才能完成,而future2需要15秒,因此,在15秒后会产生值。

  

注意:因为对于表达式,序列化其转换,所以如果   不要在for表达式之前创建期货,它们不会在   平行。

val newFuture = for {
    res1 <- Future {Thread.sleep(10000); 10}
    res2 <- Future {Thread.sleep(15000); 20}
} yield res1+res2

以上将需要至少25秒才能完成。

另一方面,如果您将一个未来的结果用于另一个,则它不会并行运行。以下代码等于future1.map(value => {Thread.sleep(15000); 20 + value})

val future1 = Future {Thread.sleep(10000); 10}
def future2(value: Int) = Future {Thread.sleep(15000); 20 + value}
val newFuture = for {
    res1 <- future1
    res2 <- future2(res1)
} yield res2

总而言之,如果您需要使用一个未来值的结果,然后使用该值执行某些计算,请使用map/flatMap。但是,如果您需要同时执行多个Future并执行这些Future的值的计算,请使用for表达式,并知道两者都是完全异步的。

答案 1 :(得分:0)

使用a进行理解的用例是取决于将来的情况。

让我们用一个例子来解释它:

FutureB 如果它依赖于 FutureA 值,则需要等待 FutureA 值的计算,然后才可以传递它转到 FutureB

有两种解决方法:

1.使用地图:

地图的基本组合器之一是地图,给定一个Future和一个针对该Future的值的映射函数,该Map会生成一个新的Future,一旦成功完成了原始的Future,就用映射值完成该新的Future。您可以以与映射集合相同的方式推理映射期货。 (取自https://docs.scala-lang.org/overviews/core/futures.html#functional-composition-and-for-comprehensions

示例:

FutureA.map(FutureB(_))

2。使用A进行理解

val result = for {
  A <- FutureA
  B <- FutureB(A)
} yield B

在上面的示例中,我们可以看到我们使用地图和平面图按各自的顺序链接了相关的期货,从而获得了结果。而且我们也无法阻止期货,因为理解力还会返回期货。

在以上两种情况下,我们都不会阻止期货,而只是对期货进行排序。

答案 2 :(得分:0)

您可以这样想:Future上所有有用的方法都会创建新的回调,该回调计划在提供的执行上下文上运行,并在回调完成执行后返回一个新的Future对象,该对象被视为done。 而且,如果一个回调依赖于另一个回调,那么它将不早于第一个完成执行。因此没有线程被阻塞。

您可以尝试在一张纸上可视化它,这通常有助于查看。