【问题标题】:Future and latency: How to prioritize the execution of some Futures over the others未来和延迟:如何优先执行某些期货而不是其他期货
【发布时间】:2015-09-09 18:32:21
【问题描述】:

我有一个 Akka/Spray.io REST 服务器,它在收到用户的请求后,将为所述用户执行三个操作:

  1. 将用户数据上传到远程存储。
  2. 更新数据库中的用户统计信息
  3. 响应用户指示操作是失败还是成功

由于它们本质上都是阻塞操作,因此它们被包裹在 scala.concurrent.Future 中以进行异步执行。

我面临的问题是,在重负载下,服务器的响应延迟非常高(5 秒)。经调查,问题是由于包含特定用户响应的Future 实例在该用户的计算完成后并未立即执行。相反,我经常发现它们排在其他任务之后。

这基本上是一个优先级问题。理想情况下,服务器继续执行异步操作,但是当用户响应可用时,它应该优先于其他任务。想象一下,我们可以对服务器说,“嘿,我知道你会有很多来自其他用户的待处理请求,但是既然你已经完成了为这个特定用户更新数据库和上传数据,为什么不先响应用户,然后再继续为其他客户服务”

我尝试设置两个 ExecutionContext 实例,responseEC,一个专用的 ExecutionContext 用于发送用户响应,generalBlockingEC 用于其他(阻塞)任务。我预计 JVM 将在两个 EC 实例之间以高度公平的方式交替执行,并看到我的响应以更及时的方式发送。

不幸的是,由于某种原因,JVM 倾向于在generalBlockingEC 上花费更多时间,而不是以公平的方式在responseEC 和generalBlockingEC 之间交替工作。

我是否以错误的方式解决问题?有没有更好的方法来优先执行某些 Future 实例而不是其他实例(例如,可能在 Actor 的帮助下)?

【问题讨论】:

  • 为什么要并行运行所有这些东西?例如,如果一个失败而另一个成功,您仍然会向用户返回失败,但缺点是在操作上浪费了一个线程,还请注意,即使您将它们包装在期货中,它们仍然会阻塞分配的线程据我所知。
  • @EndeNeu 在线程中遇到阻塞调用时,将执行上下文切换,以便另一个线程可以执行。上下文切换很昂贵,但如果调整正确(考虑到可用 CPU 的数量和平均阻塞时间等),多线程处理多个阻塞调用的速度优势仍将超过上下文切换的成本

标签: scala concurrency executorservice


【解决方案1】:

首先,我将在这里回答为什么没有一种机制可以将某些线程池优先于其他线程池:How to configure ThreadPool priority in Playframework 具体来说:

目前无法配置线程优先级,因为 设置在许多平台上几乎没有影响,因此 有资格作为安慰剂。如果您开始并积极使用更多线程 比你有 CPU 内核,那么由此产生的竞争将代价高昂 并且会浪费资源,所以你最好仔细拟合 您的线程池大小与 CPU 绑定部分的可用内核有关。

我认为您已经通过创建两个执行上下文开始了正确的路线。我建议您确保每个执行上下文都有自己的线程池,并且两者之间的线程总数不超过或不显着超过硬件上的内核数。

如果您希望一个执行上下文优于另一个,您可以尝试在线程总数中赋予它更大的比例。

【讨论】:

  • 有趣。那么,如果基本构建块对这些事情几乎没有保证,应该如何在应用程序中争取相对一致的延迟配置文件呢?也许只有我一个人,但我觉得调整线程数非常繁琐,一般来说不是一个非常强大的解决方案
  • 扩展到多台机器?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-09
  • 2023-03-03
  • 2017-11-25
  • 1970-01-01
  • 2019-06-11
  • 2014-09-23
相关资源
最近更新 更多