Почему будущее висит в переводчике?
Следующий однострочник висит в Scala REPL
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Future, future, Await}
import scala.concurrent.duration._
def fib(n: Int): Int = {println(n + " is handeled by " + Thread.currentThread.getName) ; if (n < 2) n else Await.result( Future.sequence(List(1,2) map (i => Future{println(n-i); n-i} map fib)) map (_.sum), Duration.Inf)} ; fib(3)
Его ядро
val lf: List[Future[Int]] = List(1,2) map (i => Future{n-i} map fib)
val f: Future[List[Int]] = Future.sequence(lf)
Await.result(f, Inf)
Он также висит в интерпретаторе аммонита. Он более продвинутый и позволяет прервать выполнение, и, вероятно, трассировка стека скажет вам что-то
def fib(n: Int): Int = {println(n + " is handeled by " + Thread.currentThread.getName) ; if (n < 2) n else Await.result( Future.sequence(List(1,2) map (i => Future{println(n-i); n-i} map fib)) map (_.sum), Duration.Inf)} ; fib(3)
3 is handeled by main
1
2
^C
Interrupted!
java.lang.NoClassDefFoundError: Could not initialize class ammonite.session.cmd3$
at ammonite.session.cmd3$$anonfun$fib$1$$anonfun$apply$2.apply$mcII$sp(cmd3.scala:1)
at ammonite.session.cmd3$$anonfun$fib$1$$anonfun$apply$2.apply(cmd3.scala:1)
at ammonite.session.cmd3$$anonfun$fib$1$$anonfun$apply$2.apply(cmd3.scala:1)
at scala.util.Success$$anonfun$map$1.apply(Try.scala:237)
at scala.util.Try$.apply(Try.scala:192)
at scala.util.Success.map(Try.scala:237)
at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:237)
at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:237)
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.pollAndExecAll(ForkJoinPool.java:1253)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1346)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
java.lang.NoClassDefFoundError: Could not initialize class ammonite.session.cmd3$
at ammonite.session.cmd3$$anonfun$fib$1$$anonfun$apply$2.apply$mcII$sp(cmd3.scala:1)
at ammonite.session.cmd3$$anonfun$fib$1$$anonfun$apply$2.apply(cmd3.scala:1)
at ammonite.session.cmd3$$anonfun$fib$1$$anonfun$apply$2.apply(cmd3.scala:1)
at scala.util.Success$$anonfun$map$1.apply(Try.scala:237)
at scala.util.Try$.apply(Try.scala:192)
at scala.util.Success.map(Try.scala:237)
at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:237)
at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:237)
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)
ubuntu-workspace@
Как видите, код говорит, что n=3 is handeled by main
, печатает 1 и 2 и висит. Это означает, что фьючерсы начались, но не заканчиваются. Они не переходят к выдумке, как того требует карта. Я могу заменить Future{n-i} map fib
с Future{fib(n-i)}
но ничего не меняется. Между тем, код работает в Scastie нормально. Это говорит о том, что поведение сильно зависит от контекста.
1 ответ
Это повторяющийся вопрос о запуске потоков в инициализаторах объектов.
Быстрый обходной путь заключается в использовании scala -Yrepl-class-based
,
Смежный вопрос: Scala: параллельный сбор в инициализаторе объекта вызывает зависание программы