【发布时间】:2015-09-09 18:32:21
【问题描述】:
我有一个 Akka/Spray.io REST 服务器,它在收到用户的请求后,将为所述用户执行三个操作:
- 将用户数据上传到远程存储。
- 更新数据库中的用户统计信息
- 响应用户指示操作是失败还是成功
由于它们本质上都是阻塞操作,因此它们被包裹在 scala.concurrent.Future 中以进行异步执行。
我面临的问题是,在重负载下,服务器的响应延迟非常高(5 秒)。经调查,问题是由于包含特定用户响应的Future 实例在该用户的计算完成后并未立即执行。相反,我经常发现它们排在其他任务之后。
这基本上是一个优先级问题。理想情况下,服务器继续执行异步操作,但是当用户响应可用时,它应该优先于其他任务。想象一下,我们可以对服务器说,“嘿,我知道你会有很多来自其他用户的待处理请求,但是既然你已经完成了为这个特定用户更新数据库和上传数据,为什么不先响应用户,然后再继续为其他客户服务”
我尝试设置两个 ExecutionContext 实例,responseEC,一个专用的 ExecutionContext 用于发送用户响应,generalBlockingEC 用于其他(阻塞)任务。我预计 JVM 将在两个 EC 实例之间以高度公平的方式交替执行,并看到我的响应以更及时的方式发送。
不幸的是,由于某种原因,JVM 倾向于在generalBlockingEC 上花费更多时间,而不是以公平的方式在responseEC 和generalBlockingEC 之间交替工作。
我是否以错误的方式解决问题?有没有更好的方法来优先执行某些 Future 实例而不是其他实例(例如,可能在 Actor 的帮助下)?
【问题讨论】:
-
为什么要并行运行所有这些东西?例如,如果一个失败而另一个成功,您仍然会向用户返回失败,但缺点是在操作上浪费了一个线程,还请注意,即使您将它们包装在期货中,它们仍然会阻塞分配的线程据我所知。
-
@EndeNeu 在线程中遇到阻塞调用时,将执行上下文切换,以便另一个线程可以执行。上下文切换很昂贵,但如果调整正确(考虑到可用 CPU 的数量和平均阻塞时间等),多线程处理多个阻塞调用的速度优势仍将超过上下文切换的成本
标签: scala concurrency executorservice