【问题标题】:How does scala's actor model make use of C threads and native system threads?scala 的 actor 模型如何利用 C 线程和本机系统线程?
【发布时间】:2015-02-27 11:27:34
【问题描述】:

scala 的 actor 模型如何利用 C 线程和本机系统线程? 我知道编译器是可插入的,所以 scala 编译器取代了 java 编译器。我对下一步感到困惑,代码的中间表示不是刚刚被热点优化(可能不如基于线程的模型有效)并转换为基于线程的机器代码和 C 组合。

【问题讨论】:

  • 这是一个 JVM 实现细节 - 与 Java 或 Scala 无关。它们都使用Thread 构造,该构造由 JVM 以 native 代码实现。
  • 感谢 Spider 是我感兴趣的 JVM 实现。
  • 哪个JVM?该JVM的哪个确切版本?在哪个平台上?
  • Java HotSpot 服务器虚拟机,Java SE 7 Update 60 在 Fedora 18 64 位上运行。感谢您的帮助,现在我已经足够学习使用 Vlads 答案了。

标签: java multithreading scala jvm-hotspot


【解决方案1】:

Akka如何使用原生线程的一张非常粗略的图如下。

  1. Akka Actors 是由 ActorSystem 实例化的对象
  2. 然后它们被安排在Dispatcher 上执行。
  3. Dispatcher 最终将执行委托给一些 ExecutorService
  4. DispatcherExecutorService 的实际实现决定了JVM 线程的创建和使用方式。默认情况下,使用基于 fork-join 池的执行器服务。它是用ForkJoinExecutorConfigurator 创建的,它创建了一个工厂,而工厂又创建了ExecutorService 的相应实现。
  5. Fork-join 池在内部创建多个Threads,并使用它们来执行给定的任务。实际的执行策略并不重要;还有其他执行器可以跨线程以不同方式调度任务,Akka 可以配置为使用它们而不是默认的。
  6. Thread 是在标准库中实现的 JVM 级抽象。它使用与将线程管理委托给操作系统的本机库(以某种本机语言,如 C++ 或 C 编写)的绑定。
  7. 所以,当Thread对象创建并启动时,最终会创建并启动一个本地线程,该线程将执行提供给此Thread对象的代码。

这是一个简单的演员如何执行的图表:

Actor -> Dispatcher -> ExecutorService ----> Thread --|                    |--> OS thread
                                        |--> Thread --|native code boundary|--> OS thread
                                        \--> Thread --|                    |--> OS thread

您可以看到这里有几个抽象层。最重要的是ExecutorService:它完全定义了线程实例化和在这些线程上执行任务的实际策略。可以编写一个永远不会产生额外线程的单线程执行器服务(实际上标准库中有一个),并且可以强制 Akka 使用它。

actor 的中间表示(我假设你的意思是 Java 字节码)没有直接优化为与本机线程一起使用的代码,因为它们是完全不同的抽象级别:actor 非常高-级别并提供许多关于执行顺序的保证,而线程是非常低级的,如果您希望程序正确,则必须非常小心地使用。 Akka 确保正确使用线程,因此您不必自己考虑。

【讨论】:

  • 非常好的总结,+1。
  • 我经常看到这样写“Akka 确保线程被正确使用”,但我们怎么知道呢?
  • 嗯,那是因为它是这样写的?我的意思是,这就是库作者声明的目标,并且到目前为止它确实正常工作,这得到了 Akka 在生产和开源软件中的大量使用的支持。
【解决方案2】:

当然,actor 最终是使用较低级别的工具实现的,例如 java.lang.Thread(可能会使用本机线程实现,尽管这是 JVM 的实现细节)、synchronized 和各种 Java 原子。

关键是actor提供了更好的API,保证易于推理;系统保证给定的actor一次只处理一条消息,并且将按顺序处理消息,几乎就像整个actor在一个大的synchronized块中一样——但性能比你这样做要高得多。您可以使用actor实现的任何事情,可以“手动”完成,方法是拥有一堆锁、信号量等,仔细阅读 Java 内存模型规范,并非常仔细地编写逻辑以确保所有锁都在正确的时间获得和释放,每个线程都运行它最适合的任务。但那时你基本上是在编写自己的演员系统。

【讨论】:

  • 顺序点 - 同步是与原子和 java.util.concurrent 完全不同的实现和机制
  • 只是有时。根据规范,JVM 被允许使用锁定来实现原子,因此它们可以是与同步相同的机制。即使机制不同,它们也经常用于实现相同的结果。您想在这里区分什么?
  • 在绝大多数情况下,它们在 OpenJDK 实现中是完全不同的。同步使用监视器。 j.u.concurrent 没有 - 它依赖于通过 Unsafe 提供的机制。
猜你喜欢
  • 2014-04-09
  • 2020-03-05
  • 1970-01-01
  • 2012-09-06
  • 2020-02-20
  • 2011-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多