忠实地实现actor消息传递语义意味着消息内容是从逻辑视点深度复制的,即使对于不可变类型也是如此。消息内容的深度复制仍然是实现actor模型的瓶颈,因此对于性能,一些实现支持零拷贝消息传递(尽管它仍然是程序员的观点深度拷贝)。
是否在Erlang中实现的所有零拷贝消息传递?在节点之间显然不能这样实现,但是在同一节点上的进程之间呢? This question是相关的。
答案 0 :(得分:21)
我认为你的断言根本不正确 - 深层复制进程间消息不是Erlang的瓶颈,而且使用默认的VM构建/设置,这正是所有Erlang系统正在做的事情。 / p>
Erlang进程堆彼此完全分离,并且消息队列位于进程堆中,因此必须复制消息。对于将数据传入和传出ETS表也是如此,因为它们的数据存储在与进程堆分开的单独分配区域中。
但是,有许多共享数据结构。大二进制文件(> 64字节长)通常在节点范围内分配并被引用计数。 Erlang进程只存储对这些二进制文件的引用。这意味着如果您创建一个大型二进制文件并将其发送到另一个进程,那么您只需发送引用。
在进程之间发送数据实际上在分配大小方面比您想象的要差 - 在复制期间不会保留术语内的共享。这意味着如果您仔细构建一个带共享的术语以减少内存消耗,它将在另一个进程中扩展为其非共享大小。您可以在OTP Efficiency Guide中看到一个实际示例。
正如Nikolaus Gradwohl指出的那样,VM有一个实验性的混合堆模式,它允许进程之间的术语共享并启用零拷贝消息传递。根据我的理解,它并不是一个特别有希望的实验 - 它需要额外的锁定并使流程的现有能力复杂化以独立地进行垃圾收集。因此,复制进程间消息不仅不是Erlang系统中的常见瓶颈,而且实际上会降低性能。
答案 1 :(得分:7)
AFAIK有/是使用-shared或-hybrid modell在erlang中进行零拷贝消息传递的实验性支持。我在2009年阅读了一篇博文,声称它在smp机器上被破坏了,但我不知道目前的状态
答案 2 :(得分:7)
正如此处和其他问题中所提到的,当前版本的Erlang基本上复制除了较大的二进制文件之外的所有内容。在较早的SMP之前,不可复制但传递引用是可行的。虽然这导致了非常快速的消息传递,但它在实现中产生了其他问题,主要是它使垃圾收集更加困难和复杂的实现。我认为今天传递引用和共享数据可能导致过度锁定和同步,这当然不是一件好事。
答案 3 :(得分:4)
我写了你正在引用的另一个问题的接受答案,在其中我直接指向这行代码:
message = copy_struct(message, msize, &hp, &bp->off_heap);
这是在Erlang运行时系统需要发送消息时调用的函数,并且它不在任何可能导致它被跳过的“if”内。所以,据我所知,答案是“是的,它总是被复制的”。 (这不是严格正确的 - 有一个“if”,但它似乎处理异常情况,而不是正常的代码流路径。)
(我忽略了Nikolaus提出的混合堆选项。看起来他是对的,但由于这不是Erlang通常建造的方式而且它有自己的处罚,我不认为它是值得的考虑作为回答你问题的一种方式。)
我不知道为什么你会考虑10 GByte / sec的瓶颈。在计算机中没有任何简单的寄存器或CPU缓存变得更快,并且这样的存储器很小,因此自身构成了一种瓶颈。除此之外,你提出的零拷贝思想在多核系统中跨CPU消息传递的情况下需要锁定,这也是一个瓶颈。我们已经在此函数中支付了一次锁定惩罚,将消息复制到另一个进程的消息队列中;为什么稍后当这个过程到处阅读消息时再付钱?
最重要的是,我认为你想要让它变得更快的想法实际上会有所帮助。