我发现这有点令人困惑。我认为scala中的future是一次设置的不可变容器,总是返回相同的值。
所以我有一个未来:
val y = future {Thread.sleep(1000); 1};
现在,当我立即(在未来解决之前)将其传递给Await.result
阻止两次:
Await.result(for (r1 <- y; r2 <- y) yield (r1, r2), 60 seconds)
我得到TimetoutException
。
但是如果我在未来解决后再这样做,一切正常并按预期返回(1,1)
。
这种行为的原因是什么?
编辑:
我正在使用隐式ExecutionContext.Implicits.global
和scala.concurrent
@ scala 2.10.3
EDIT2: 如果我创建另一个未来的实例做同样的事情,并对它们执行Await.result,它都不会阻塞。
答案 0 :(得分:3)
这似乎是在REPL中执行它的工件。
您甚至可以使用2个单独的未来实例重现它,而无需调用Thread.sleep
,
并且仅使用预先履行的期货(这意味着甚至没有任何未来的线程被调用)。
是的,严肃地说:
import scala.concurrent._
import duration._
import ExecutionContext.Implicits.global
val x = Future.successful(1)
val y = Future.successful(2)
Await.result(x.flatMap{_ => y.map{ _ => 0 } }, Duration(10, SECONDS)) // triggers a timeout
有趣的是,如果你将最后一行改为:
,这不会触发任何超时Await.result(x.flatMap{_ => Future.successful(2).map{ _ => 0 } }, Duration(10, SECONDS))
似乎culprint是你的整个代码片段,当在REPL中被证实时,实际上是包装在一个对象中。
这意味着x
和y
实际上是对象的成员,而不是局部变量
更重要的是,对Await的调用现在是此包装器对象的构造函数的一部分。
由于某些原因我尚未调查,似乎是Await
的调用是在触发阻塞的构造函数中完成的
(您可以通过将此调用包装在虚拟类中并实例化它来轻松验证它。)
答案 1 :(得分:2)
只是补充堆栈跟踪,当闭包类需要X.z
时失败:
apm@mara:~$ goof
Welcome to Scala version 2.11.0-RC3 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.concurrent._
import scala.concurrent._
scala> import duration._
import duration._
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> object X { val y = Future { 9 } ; val z = Future { 7 } ; val r = Await.result(for (a <- y; b <- z) yield (a+b), 5.seconds) }
defined object X
scala> X.r
java.lang.NoClassDefFoundError: Could not initialize class $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$X$
at $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$X$$anonfun$3.apply(<console>:14)
at $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$X$$anonfun$3.apply(<console>:14)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:251)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:121)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
java.util.concurrent.TimeoutException: Futures timed out after [5 seconds]
at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:219)
at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:223)
at scala.concurrent.Await$$anonfun$result$1.apply(package.scala:111)
at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
at scala.concurrent.Await$.result(package.scala:111)
... 34 elided
只是为了证明它有效:
apm@mara:~$ goof -Yrepl-class-based
Welcome to Scala version 2.11.0-RC3 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.concurrent._
import scala.concurrent._
scala> import duration._
import duration._
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> object X { val y = Future { 9 } ; val z = Future { 7 } ; val r = Await.result(for (a <- y; b <- z) yield (a+b), 5.seconds) }
defined object X
scala> X.r
res0: Int = 16