由于某些原因,我无法理解如何实现这个功能。我有一个应用程序运行,其中包含调用Elastic Search的Play。作为我的设计的一部分,我的服务使用Java API,通过scala future进行封装,如博客文章所示。我已经更新了代码,以提示ExecutionContext将执行一些阻塞I/O操作,如下所示:
import scala.concurent.{blocking, Future, Promise}
import org.elasticsearch.action.{ActionRequestBuilder, ActionListener, ActionResponse }
def execute[RB <: ActionRequestBuilder[_, T, _, _]](request: RB): Future[T] = {
blocking {
request.execute(this)
promise.future
}
}
我的实际服务会构造查询并将其发送到ES,它会将executionContext作为构造函数参数使用,然后用于对elastic search的调用。我这样做是为了避免play使用的全局执行上下文受到对ES的阻塞调用而被阻塞。这个S.O.评论提到只有全局上下文具有阻塞感知能力,因此我必须自己创建一个。在同一篇帖子/答案中,有很多关于使用ForkJoin池的信息,但我不确定如何将这些文档中的内容与阻塞文档中的提示结合起来,以创建一个响应阻塞提示的执行上下文。
我认为我的一个问题是,我不确定如何在第一时间对阻塞上下文做出响应?我正在阅读最佳实践,它使用的示例是一个无界线程缓存:那么,这是否意味着在使用我的ForkJoin支持的线程池时,当处理非阻塞I/O时应该尝试使用缓存线程,并为阻塞I/O创建新线程?还是其他什么?我在网上找到的几乎所有关于使用单独线程池的资源都倾向于像初学者指南所做的那样:如何调整各种线程池高度依赖于您的个人应用程序,超出了本文的范围。请注意,我更喜欢使用无界“缓存线程池”,因此它没有限制。当进行阻塞I/O时,想法是您必须拥有足够的线程来阻塞。但是,如果无限制太多,根据用例,您可以稍后进行微调,这个示例的想法是让您开始工作。
我知道它取决于您的应用程序,但在这种情况下,如果我只想创建某种阻塞感知ExecutionContext并了解管理线程的良好策略。如果Context专门用于应用程序的某个部分,那么我应该只制定一个固定的线程池大小,而不使用/忽略首先出现的
blocking
关键字吗?我倾向于冗长,因此我将尝试分解我在答案中寻找的内容:
- 编程!阅读所有这些文档仍然让我感觉像是离能够编写一个阻塞感知上下文还有一步之遥,我真的很需要一个例子。
- 有关如何处理阻塞线程的任何链接或提示,例如为它们创建一个无限的新线程、检查可用线程数量并在太多时拒绝,或者其他策略。
- 我不是在寻找性能提示,我知道只有通过测试才能获得那个,但如果我无法弄清楚如何首先编写上下文,我就无法进行测试!我找到了 ForkJoins vs threadpools 的示例,但我缺少关于
blocking
的重要部分。
对于这个冗长的问题,我很抱歉,我只是想让您了解我正在看什么,并且我已经试图理解这个问题超过一天,需要一些外部帮助。
编辑:仅为明确起见,ElasticSearch服务的构造函数签名是:
//Note that these are not implicit parameters!
class ElasticSearchService(otherParams ..., val executionContext: ExecutionContext)
在我的应用程序启动代码中,我有类似这样的东西:
object Global extends GlobalSettings {
val elasticSearchContext = //Custom Context goes here
...
val elasticSearchService = new ElasticSearchService(params, elasticSearchContext);
...
}
我也在阅读Play的上下文建议,但尚未看到有关阻止提示的任何内容,我怀疑我可能需要查看源代码以查看它们是否扩展了BlockContext
特质。
val executorService = Executors.newFixedThreadPool(someNumberFromConf); val executionContext = ExecutionContext.fromExecutorService(executorService)
? 我有点困惑当一个执行上下文改变时会发生什么,我的控制器代码使用全局隐式来响应 Action.async,但控制器本身调用服务,该服务将使用另一个上下文。你有任何关于Scala如何处理这个问题的想法吗?我不禁要想系统是如何在上下文之间切换的 - EdgeCaseBergExecutionContext
作为构造函数参数。在那段代码中,当调用ES时,只需要确保使用了一个即可。在那个特定的Scala文件中,不要导入全局隐式的ExecutionContext
。我想你使用调用ES的库需要一个ExecutionContext
,只需确保使用这个即可。 - cmbaxter