出于某种原因,我无法解决这个问题。我有一个与Play一起运行的应用程序,它调用Elastic Search。作为我设计的一部分,我的服务使用了用 scala future 包装的 Java API,如这篇博文所示。我已经更新了该帖子中的代码,以提示 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 作为构造函数参数,然后用于调用弹性搜索。我这样做是为了让 play 使用的全局执行上下文不会因为对 ES 的阻塞调用而束缚住它的线程。这个 SO 评论提到只有全局上下文是阻塞感知的,所以我不得不创建自己的。在同一个帖子/答案中,有很多关于使用 ForkJoin 池的信息,但我不确定如何将这些文档中的内容与阻塞文档中的提示结合起来,以创建响应阻塞的执行上下文提示。
我认为我遇到的一个问题是我不确定首先如何响应阻塞上下文?我正在阅读最佳实践,它使用的示例是无限的线程缓存:
请注意,这里我更喜欢使用无界的“缓存线程池”,因此它没有限制。在进行阻塞 I/O 时,想法是您必须有足够的线程可以阻塞。但是,如果 unbounded 太多了,根据用例,您可以稍后对其进行微调,这个示例的想法是让球滚动。
那么这是否意味着对于我的 ForkJoin 支持的线程池,我应该在处理非阻塞 I/O 时尝试使用缓存线程并为阻塞 IO 创建一个新线程?或者是其他东西?我在网上找到的关于使用单独线程池的几乎所有资源都倾向于执行Neophytes 指南所做的事情,也就是说:
如何调整各种线程池高度依赖于您的个人应用程序,超出了本文的范围。
我知道这取决于您的应用程序,但在这种情况下,如果我只想创建某种类型的阻塞感知 ExecutionContext 并了解管理线程的体面策略。如果上下文专门针对应用程序的单个部分,我应该只制作固定的线程池大小而不是blocking
首先使用/忽略关键字吗?
我倾向于漫无边际,所以我会尝试分解我在答案中寻找的内容:
- 代码!阅读所有这些文档仍然让我感觉自己无法编写阻塞感知上下文,我真的很感激一个例子。
- 关于如何处理阻塞线程的任何链接或提示,即无休止地为它们创建一个新线程,检查可用线程的数量,如果太多则拒绝,其他一些策略
- 我不是在这里寻找性能提示,我知道我只能通过测试来获得它,但是如果我一开始就无法弄清楚如何对上下文进行编码,我就无法测试!我确实找到了 ForkJoins 与线程池的示例,但我错过了
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 对 contexts 的建议,但还没有看到任何关于阻止提示的内容,我怀疑我可能需要查看源代码以查看它们是否扩展了BlockContext
特征。