在 Erlang/OTP 中调用 gen_server 的开销是多少?

What's the overhead for gen_server calls in Erlang/OTP?

这个关于 Erlang 可伸缩性的 post 表示对 gen_server 的每次调用、强制转换或消息都会产生开销。它有多少开销,它有什么用?

被引用的成本是对外部模块的(相对盲目的)函数调用的成本。发生这种情况是因为 gen_* 抽象中的所有内容都是对外部定义函数(您在回调模块中编写的函数)的回调,而不是可以由编译器在单个模块中优化的函数调用。该成本的一部分是调用的分辨率(找到要执行的正确代码——与 Python 或 Java 中的每个 "dot" in.a.long.function.or.method.call 提高成本的相同原因分辨率),另一部分成本是实际调用本身。

但是

这不是您可以计算为一个简单的数量然后乘以得到关于整个系统的运营成本的有意义答案的东西。

在像 Erlang 这样的大规模并发系统中,有太多的变量、约束点和出乎意料的廉价元素,其中最难的并发部分被抽象掉(与调度相关的问题),而并行处理的最昂贵的元素被制作出来非常便宜(上下文切换,进程 spawn/kill 和 process:memory 比率)。

真正了解大规模并发系统(其本质上会表现出紧急行为)的唯一方法是编写一个并在实际操作中对其进行测量。您可以使用 gen_* 抽象在纯 Erlang 中一次又一次地编写完全相同的程序作为 OTP 应用程序,并以这种方式衡量性能差异——但基准测试数字只对那个特定程序有任何意义 并且可能仅表示任何 在该特定负载配置文件下

考虑到所有这些......当我们开始在 Erlang 世界中分裂头发时真正重要的数字是减少调度程序的预算成本 takes into account. Lukas Larsson at Erlang Solutions put out a video a while back about the scheduler and details the way these costs impact the system, what they are, and how to tweak the values under certain circumstances (Understanding the Erlang Scheduler). Aside from external resources (iops delay, network problems, NIF madness, etc.) that have nothing to do with Erlang/OTP the overwhelming factor is the behavior of the scheduler,而不是 "cost of a function call"。

不过,在所有情况下,真正了解的唯一方法是编写一个原型来表示您在实际系统中期望的基本行为并对其进行测试。