我确实知道如何创建自己的 ExecutionContext 或导入全局播放框架。但我必须承认,我远不是关于多重上下文/执行服务如何在后面工作的专家。
所以我的问题是,为了更好的服务性能/行为,我应该使用哪个 ExecutionContext?
我测试了两个选项:
import play.api.libs.concurrent.Execution.defaultContext
和
implicit val executionContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()))
两者都产生了可比的性能。
我使用的动作在 playframework 2.1.x 中是这样实现的。SedisPool 是我自己的对象,带有一个普通的 sedis/jedis 客户端池的额外 Future 包装。
def testaction(application: String, platform: String) = Action {
Async(
SedisPool.withAsyncClient[Result] { client =>
client.get(StringBuilder.newBuilder.append(application).append('-').append(platform).toString) match {
case Some(x) => Ok(x)
case None => Results.NoContent
}
})
}
这种性能方面的表现与 Node.js 和 Go 中完全相同的函数一样好或稍慢。但仍然比 Pypy 慢。但是比 Java 中的同样事情要快得多(在这种情况下,使用 jedis 对 redis 进行阻塞调用)。我们使用 gatling 进行负载测试。我们在 redis 之上进行简单服务的技术“竞争”,标准是“与编码人员一样多的努力”。我已经使用 fyrie 测试了它(除了我不喜欢 API 的事实)它的行为几乎与这个 Sedis 实现相同。
但这不是我的问题。我只是想了解更多关于 playframework/scala 的这一部分。
有建议的行为吗?或者有人可以为我指出一个更好的方向吗?我现在开始使用 scala,我远不是专家,但我可以自己完成代码答案。
谢谢你的帮助。
更新 - 更多问题!
篡改池中的线程数后发现:Runtime.getRuntime().availableProcessors() * 20
为我的服务提供了大约 15% 到 20% 的性能提升(以每秒请求数和平均响应时间来衡量),这实际上使它比 node.js 和 go 稍微好一点(尽管几乎没有)。所以我现在有更多问题: - 我测试了 15 倍和 25 倍,而 20 似乎是一个最佳点。为什么?有任何想法吗?- 会有其他更好的设置吗?其他“甜蜜点”?- 20x 是最佳点还是取决于我正在运行的机器/jvm 的其他参数?
更新 - 有关该主题的更多文档
找到有关播放框架文档的更多信息。 http://www.playframework.com/documentation/2.1.0/ThreadPools
对于 IO,他们确实对我所做的事情提出了一些建议,但提供了一种通过 Akka.dispatchers 进行操作的方法,该方法可通过 *.conf 文件进行配置(这应该让我的操作很高兴)。
所以现在我正在使用
implicit val redis_lookup_context: ExecutionContext = Akka.system.dispatchers.lookup("simple-redis-lookup")
调度程序由
akka{
event-handlers = ["akka.event.slf4j.Slf4jEventHandler"]
loglevel = WARNING
actor {
simple-redis-lookup = {
fork-join-executor {
parallelism-factor = 20.0
#parallelism-min = 40
#parallelism-max = 400
}
}
}
}
它给了我大约 5% 的提升(现在正在关注它),并且一旦 JVM “热”,性能就会更加稳定。我的管理员很乐意在不重建服务的情况下使用这些设置。
我的问题仍然存在。为什么会有这个数字?