Scala和Java期货显然有意想不到的相互作用

时间:2014-03-17 14:52:26

标签: java multithreading scala concurrency scala-java-interop

我们在Scala Play Framework应用程序中使用Elasticsearch 0.90.7,我们的" doSearch"方法如下:

def doSearch(...) = {
  ...
  val actionRequessBuilder: ActionRequestBuilder // constructed earlier in the method
  val executedFuture: ListenableActionFuture<Response> = actionRequestBuilder.execute
  return executedFuture.actionGet
}

其中ListenableActionFuture延伸java.util.concurrent.Future,而ListenableActionFuture#actionGet基本上与Future#get相同

当我们按顺序执行搜索时,这一切都正常,但是当我们尝试并行执行多个搜索时:

val search1 = scala.concurrent.Future(doSearch(...))
val search2 = scala.concurrent.Future(doSearch(...))
return Await.result(search1, defaultDuration) -> Await.result(search2, defaultDuration))

我们有时(不到1%或2%的时间)在我们的scala期货上获得意外超时,即使在qa期间使用极长的超时(5秒,搜索总是在不到200毫秒内执行) )。使用scala全局执行上下文以及使用Play默认执行上下文时也会发生这种情况。

由于Java未来包含在scala未来,是否存在某种意外的交互?我原以为actionGet doSearch {{1}} {@}} {@}} {@}} {@}} {@}} {{}} {}} {{{{{{{{{{{{{{{

1 个答案:

答案 0 :(得分:2)

我认为它建立在某个地方,阻止是邪恶的。恶!

在这种情况下,Await.result将阻止当前线程,因为它正在等待结果。

Await将调用包装在blocking中,试图通知线程池它可能希望增长一些线程以维持其所需的并行性并避免死锁。

如果当前线程不是Scala BlockContext,那么您只会受到阻塞。

无论你的精确配置是什么,大概是你在被阻止的时候抓住了一个线程,而你为了搜索而运行的thunk想要运行某些东西并且因为游泳池耗尽而无法运行。

什么相关的是什么池产生了当前的线程:中间的Future是否在不同的池上并不重要,如果在底部,你需要使用当前池中的更多线程和它已经筋疲力尽了。

当然,这只是猜测。

让一个单一的未来从两次搜索中获得价值更有意义,并且超时。

但是如果你结束了多个期货,那么使用Future.sequence并等待它就有意义了。