// 1 fixed thread
implicit val waitingCtx = scala.concurrent.ExecutionContext.fromExecutor(Executors.newFixedThreadPool(1))
// "map" will use waitingCtx
val ss = (1 to 1000).map {n => // if I change it to 10 000 program will be stopped at some point, like locking forever
service1.doServiceStuff(s"service ${n}").map{s =>
service1.doServiceStuff(s"service2 ${n}")
}
}
每个doServiceStuff(name:String)
需要5秒钟。 doServiceStuff没有隐式ex:执行上下文作为参数,它在内部使用自己的ex上下文,并在其上执行Future {blocking { .. }}
。
在最后的节目中打印:
took: 5.775849753 seconds for 1000 x 2 stuffs
如果我将1000更改为 10000 ,则添加更多任务:val ss = (1 to 10000)
然后程序停止:
~17 027行将打印出来(20 000)。不#34;错误"信息 将被打印。不,"采取"消息将被打印
**并且不会再进一步处理。
但是,如果我将exContext更改为ExecutionContext.fromExecutor(null: Executor)
(全局一个),则会在大约10秒内结束(但通常不会)。
~17249 lines printed
ERROR: java.util.concurrent.TimeoutException: Futures timed out after [10 seconds]
took: 10.646309398 seconds
这就是问题所在 :为什么使用固定的前上下文池会停止而不发送消息,但是对于全局前上下文,它会终止,但会出现错误和消息?
有时......它不可复制。
更新:如果我将游泳池从1增加到N,我确实会看到"ERROR"
和"took"
。无论N是多么高 - 它将是错误。
代码在这里:https://github.com/Sergey80/scala-samples/tree/master/src/main/scala/concurrency/apptmpl
答案 0 :(得分:0)
我想我知道发生了什么。如果你眯着眼睛,你会发现map
职责是非常轻量级的:只是开启一个新的未来(因为doServiceStuff是一个未来)。我敢打赌,如果切换到flatMap
,行为将会改变,这实际上会使嵌套的未来变平,因此将等待第二次doServiceStuff
调用完成。
由于你没有把这些未来弄平,所有等待下游的人都在等待错误的事情,而你却没有抓住它,因为here你放弃了任何服务回报。
更新
好的,我误解了你的问题,虽然我仍然认为嵌套的Future是一个错误。
当我使用10000任务的两个执行程序尝试你的代码时,我在OutOfMemory
执行上下文(即ForkJoin
任务)中创建线程时得到service
,我就是这样做的期望。您使用了任何特定的内存设置吗?
有1000个任务,他们都成功完成。