【问题标题】:Reductions in the Erlang BEAM machineErlang BEAM 机器的缩减
【发布时间】:2025-11-27 07:10:01
【问题描述】:

Erlang 是一种著名的编程语言(除其他外) 因为它是轻量级线程。 Erlang 通常使用BEAM machine 实现。 Erlang BEAM 机器的描述(H'97)说

为了保证公平调度,一个进程在一个固定的时间后被挂起 reductions 的次数,然后队列中的第一个进程是 已恢复。

我对这种减少的概念很感兴趣。根据 (H'97),只有以下 BEAM 命令算作减少:

  • C/CO/ResC:调用本地/常驻Erlang函数
  • CL:丢弃当前堆栈帧。调用本地 Erlang 函数。
  • CEx/TrCEx:调用外部 Erlang 函数(跟踪或其他方式)。
  • CExL/TrCExL:丢弃当前堆栈帧并调用外部 Erlang 函数(跟踪或其他方式)。
  • M_C_r:加载参数寄存器 x(0)。调用常驻 Erlang 函数。
  • M_CL_r:加载参数寄存器 x(0)。丢弃当前堆栈帧。调用本地 Erlang 函数。

所有这些都涉及函数调用。 相反,对 C 函数的调用(例如 TrC/TrCO)和对内置函数的调用(例如由 Bif_0_ 调用)不算作 减少。

问题。在这个序言之后,这是我想知道的。

  1. 为什么线程之间的调度使用缩减而不是时间片?
  2. 为什么只有上述命令会推进减少计数器?
  3. (H'97) 中的描述有点过时,当代 Erlang 是如何处理调度的?

(H'97)B. Hausman,The Erlang BEAM Virtual Machine Specification

【问题讨论】:

    标签: multithreading concurrency erlang scheduling vm-implementation


    【解决方案1】:

    我会尽力回答你的问题。

    1) 不使用时间片的主要原因是性能和可移植性。从操作系统读取一个单调的时间值是相当昂贵的,如果我们必须为每个函数调用都这样做,开销就会变得非常大。在不同的操作系统上,成本也有很大差异。然而,减少计数机制只要求机器擅长递减整数,大多数机器都是这样。

    2) 他们没有。正如您所说,该列表非常过时。从那以后,VM 的大部分工作方式都被重写了。作为一般经验法则;函数调用(不是返回)或任何可能花费未知时间的东西都会减少。这包括 bifs、nifs、gc、发送/接收消息以及我现在想不到的更多内容。

    3) 调度和抢占是非常不同的事情。您可能想看看我几年前举办的关于如何安排时间的网络研讨会:https://www.youtube.com/watch?v=tBAM_N9qPno

    【讨论】:

    • @Lucas,谢谢。这是非常有用的。我想知道是否有一种方法可以编写(长的、直线的)Erlang 程序来占用 CPU,因为它们不涉及减少减少计数器的代码。
    • 是的,但是因为 Erlang 除了函数调用之外没有循环结构,这只是一个理论上的问题。
    • @Lucas 没错,但即使你稍微展开一个函数,比如 4 次递归展开,与原始函数相比,你应该在 CPU 上获得大约 4 倍的时间。并不是说这是实践中的问题。
    【解决方案2】:

    我只知道第一个问题的答案:

    1. 时间片不一定在所有平台和操作系统上都是准确的;使用归约可确保所有环境中的行为一致

    【讨论】:

    • 谢谢。在什么意义上减少步骤是精确的?毕竟算作reduction的命令在不同平台上的持续时间是不一样的。
    • 它们在相对于彼此和成本方面将成比例地相等。