akka jvm threads vs os threads when performing io

2022-09-03 13:25:41

我已经搜索了一下该网站,以帮助理解这一点,但没有找到任何超级清晰的东西,所以我想我会发布我的用例,看看是否有人能提供一些启示。

我有一个关于在akka中用于io操作时jvm线程与os线程的缩放的问题。从阿卡网站:

Akka 支持事件驱动的轻量级线程和基于线程的 Actor 的调度程序,前者允许在单个工作站上创建数百万个线程,后者将每个调度程序绑定到专用的 OS 线程。

基于事件的Actor目前每个Actor消耗约600个字节,这意味着您可以在4 G RAM上创建超过650万个Actor。

在这种情况下,你们能否帮助我理解这在只有1个处理器的工作站上的重要性(为简单起见)。因此,对于我的示例用例,我想列出1000个“用户”,然后查询一个(或多个)数据库以获取有关每个用户的各种信息。因此,如果我将这些“get”任务中的每一个都分派给一个Actor,并且该Actor将要执行IO,那么该actor不会基于工作站的os线程限制来阻止吗?

在这样的场景中,akka演员模型如何给我提升?我知道我可能错过了一些东西,因为我对vm线程与os线程的互通并不了解,所以如果这里的一个聪明人能为我拼出来,那就太好了。

如果我使用期货,我不需要使用 await() 或 get() 来阻止并等待回复吗?

在我的用例中,无论参与者是谁,它最终是否只会“感觉”我发出了1000个顺序数据库请求?

如果代码片段有助于帮助我理解这一点,那么Java将是首选,因为我仍在加快scala语法的速度 - 但是对于这些数百万线程如何在执行数据库IO的同时在单处理器机器上进行互操作的漂亮清晰的文本解释也很好。


答案 1

真的很难弄清楚你在这里实际问的是什么,但这里有一些提示:

  • 如果您在现代 JVM 上运行,则 Java 线程和操作系统线程之间通常存在一对一的关系。(IIRC,Solaris允许您以不同的方式执行此操作...但这是例外。

  • 使用线程或基于线程构建的任何内容将获得的实际并行度量受应用程序可用的处理器/内核数量的限制。除此之外,您会发现并非所有线程在任何给定时刻实际上都在执行。

  • 如果有 1000 个 Actor 都试图“同时”访问数据库,那么他们中的大多数实际上将等待数据库本身或线程调度程序。这是否相当于发出1000个顺序请求(即严格的序列化)将取决于数据库和参与者正在执行的查询/更新。

底线是计算机系统对可用于做事的资源有硬性限制;例如,处理器数量、处理器速度、内存带宽、光盘访问时间、网络带宽等。您可以将应用程序设计为对使用可用资源的方式很聪明,但您无法让它使用比实际更多的资源。


在阅读您引用的文本时,在我看来,它正在谈论两种不同的演员

基于线程的参与者与线程具有 1:1 的关系。你不可能在4Gb内存中拥有数百万个这种演员。

基于事件的参与者的工作方式不同。他们不是一直都有线程,而是坐在队列中等待事件发生。发生这种情况时,事件处理线程将从队列中抓取参与者并执行与事件关联的“操作”。操作完成后,线程移动到另一个参与者/事件对上。

引用的文本表示,基于事件的执行组件的内存开销约为 600 字节。它们不包括事件线程...因为事件线程由多个参与者共享。


现在我不是Scala / Actor的专家,但很明显,在使用基于事件的Actor时,你应该避免某些事情。例如,您可能应该避免直接与外部数据库通信,因为这容易阻塞事件处理线程。


答案 2

我认为那里可能有错别字。我想他们的意思是说:

Akka 支持事件驱动的轻量级 actor 和基于线程的 Actor 的调度程序,前者允许在单个工作站上创建数百万个 Actor,后者将每个 actor 绑定到专用的 OS 线程。

事件驱动的执行组件使用线程池 - 所有(可能数百万个)执行组件共享同一个线程池。我对 Akka actor 不是很熟悉,但通常你不想用事件驱动的 Actor 来阻止 I/O,否则可能会导致饥饿。