11

Actor 消息传递语义的忠实实现意味着消息内容是从逻辑角度深度复制的,即使对于不可变类型也是如此。消息内容的深度复制仍然是actor模型实现的瓶颈,因此为了性能,一些实现支持零复制消息传递(尽管从程序员的角度来看它仍然是深度复制)。

Erlang 中是否实现零拷贝消息传递?在节点之间显然不能这样实现,但是在同一节点上的进程之间呢?这个问题是相关的。

4

4 回答 4

22

我认为您的断言根本不正确-进程间消息的深度复制不是 Erlang 的瓶颈,并且使用默认的 VM 构建/设置,这正是所有 Erlang 系统正在做的事情。

Erlang进程堆之间是完全分开的,消息队列位于进程堆中,所以消息必须被复制。这对于将数据传入和传出 ETS 表也是如此,因为它们的数据存储在与进程堆不同的分配区域中。

然而,有许多共享数据结构。大型二进制文件(>64 字节长)通常分配在节点范围的区域中并进行引用计数。Erlang 进程只存储对这些二进制文件的引用。这意味着如果您创建一个大型二进制文件并将其发送到另一个进程,那么您只是发送了引用。

就分配大小而言,在进程之间发送数据实际上比您想象的要糟糕 - 在复制期间不会保留术语内的共享。这意味着,如果您仔细构造一个带有共享的术语以减少内存消耗,它将在其他进程中扩展到其非共享大小。您可以在 OTP效率指南中看到一个实际示例。

正如 Nikolaus Gradwohl 指出的那样,VM 有一个实验性的混合堆模式,它确实允许进程之间的术语共享并启用零拷贝消息传递。据我了解,这并不是一个特别有前途的实验——它需要额外的锁定并使进程独立垃圾收集的现有能力复杂化。因此,复制进程间消息不仅不是 Erlang 系统中常见的瓶颈,而且实际上会降低性能。

于 2010-08-04T18:43:45.430 回答
7

正如这里和其他问题所提到的,当前版本的 Erlang 基本上复制了除了较大的二进制文件之外的所有内容。在 SMP 之前的旧时代,不复制但传递引用是可行的。虽然这导致消息传递非常快,但它在实现中产生了其他问题,主要是它使垃圾收集更加困难和复杂的实现。我认为今天传递引用和共享数据可能会导致过度锁定和同步,这当然不是一件好事。

于 2010-08-05T23:53:33.600 回答
7

AFAIK 使用 -shared 或 -hybrid 模型对 erlang 中的零拷贝消息传递提供了实验性支持。我在 2009 年阅读了一篇博客文章,声称它在 smp 机器上已损坏,但我不知道当前状态

于 2010-08-04T14:35:25.330 回答
4

我为您引用的其他问题写了公认的答案,并在其中为您提供了指向这行代码的直接指针:

message = copy_struct(message, msize, &hp, &bp->off_heap);

这是在 Erlang 运行时系统需要发送消息时调用的函数中,它不在任何可能导致它被跳过的“if”中。所以,据我所知,答案是“是的,它总是被复制的”。(严格来说这不是真的——有一个“如果”,但它似乎是在处理例外情况,而不是正常的代码流路径。)

(我忽略了 Nikolaus 提出的混合堆选项。看起来他是对的,但由于这不是 Erlang 通常构建的方式并且它有自己的惩罚,我认为它不值得考虑作为方法来回答您的问题。)

不过,我不知道您为什么认为 10 GByte/sec 是瓶颈。寄存器或 CPU 缓存在计算机中运行速度更快,而这些内存很小,因此本身就构成了一种瓶颈。除此之外,您提出的零拷贝想法需要在多核系统中跨CPU消息传递的情况下进行锁定,这也是一个瓶颈。我们已经在这个函数中支付了一次锁定惩罚,将消息复制到另一个进程的消息队列中;为什么稍后在该过程开始阅读消息时再次付款?

最重要的是,我认为您关于使其更快的方法的想法实际上并没有太大帮助。

于 2010-08-04T21:15:33.270 回答