Elixir进程并没有共享堆内存

时间:2017-10-14 17:49:01

标签: process erlang elixir heap

Elixir进程有自己的堆。 如果进程想要与另一个进程共享数据结构,那怎么可能呢? 我想到的一个答案是,该进程向包含数据结构的其他进程发送消息。 这是否意味着整个数据结构从一个堆复制到另一个堆?如果这是真的,那么它效率不高吗?

1 个答案:

答案 0 :(得分:7)

TL; DR:

是的,效率低下。但是你几乎从来没有在实践中注意到这一点。欢迎来到更安全的编程的世界。您可能使用基于Erlang的语言的大部分内容都与网络相关,而网络到目前为止更大的约束(有时是磁盘或端口IO)。

此外,替代方案是怪异的噩梦。无论如何,如果你进行大规模的并发编程。

讨论

在考虑"效率"时,需要考虑两种截然不同的背景:

  • 机器在时间,空间和锁定资源方面执行任务是否有效?是否有明显的快捷方式不会引入漏洞抽象?
  • 人类写作,理解和维护是否有效?

当你考虑效率的这两个方面时,你最终必须将问题归结为时间和金钱 - 因为事情在有用地使用方面实际上是重要的工具。

人类背景

这个效率论证非常类似于#34; Python的效率低于汇编程序"。我曾经争论同样的事情 - 直到我负责几项大型开发工作。我仍然认为JavaScript,XML和其他一些明显不好的语言和数据表示是魔鬼,但在一般情况下(定义为"你不喜欢的情况) t具有对中断定时的精确知识和控制,因为它与总线读/写和CPU周期有关")语言提供的基本抽象(和较小的那种语言)越大,更好。

Erlang在现代大规模并发系统环境中的每一项措施中都取胜,甚至在简单和语法限制方面压缩了大多数其他EVM语言(除了LFE - Richard得到了那是对的,imo)。

例如,考虑Elixir的syntactic complexity。它绝不是一种语言(恰恰相反)。但是对于许多新手而言,熟悉 任何初始学习曲线。 "Easy" is not at all the same thing as "simple"; "缓解"是熟悉的问题,而不是实用价值。

机器上下文

范式是否有效执行几乎完全取决于引用传递的上下文("通过指针")VS消息传递("按值")在底层实现中

传递的东西有多大?是否采用了混合方法,不会破坏按值传递消息的抽象?

在Erlang(以及扩展的Elixir和LFE)在进程之间传递的大多数消息非常小。事实上,真的很小。大的,不可变的消息几乎总是Erlang二进制文件 - 这些 通过引用传递(稍后会详细介绍)。

大型消息更为罕见,但考虑到实现复制的方式,即使这也不是一个大问题。允许进程在自己的上崩溃允许每个进程拥有its own garbage collection schedule(而不是不可预测的噩梦场景"停止世界"垃圾收集)每个Erlang进程有自己的堆。

这是两种方式的整体优化:

  • 这允许每个进程崩溃而不会影响任何内容。
  • 它还允许以某种方式编写每个进程,这样一般来说,每个赋值都是一个不可变的标签声明,而不是一个可变的赋值(而不是一个疯狂的危险和/或非常复杂的管理和 schedule 共享数据对象声明)。

所有这些都是为每个进程启用隔离垃圾收集的原因,而这个单一的区别使得Erlang 感觉就像它有增量垃圾收集,同时实际上在下面实现了一个无聊的普通GC模型(只是将它分开处理)。

但是有一些地方我们确实希望以牺牲底层复杂性(并根据程序员的认知开销方面的难度)来进行一些传递参考。

"大"二进制文件是经典的示例案例。默认情况下,任何大于64字节的二进制文件都是共享对象,通过引用(指针)传递,而不是通过值(复制)传递。当然,它们仍然是不可改变的,这是安全的唯一原因。问题是,如果不使用binary:copy/1,2,对较大二进制文件的子部分的任何引用都会成为对整个二进制文件的引用,因此您可以结束由于二进制引用内存中较大的整体二进制对象的微小片段,因此全局堆中的数量惊人的底层数据。这是有问题的,但这是在安全并发环境中实现性能攻击的价格,如共享内存对象。

结论(一些无法量化的基于轶事的指导......)

我个人而言,实际上从来没有将按值复制成为瓶颈。不止一次。我已经写了一个很多的Erlang程序。

您真正的瓶颈几乎总是共享访问外部资源,例如磁盘/存储/网络(从概念上讲,它们是相同的)。无论如何,支付额外的核心或额外的VM /实例比支付程序员追踪应该使用binary:copy/1,2的情况和速度更便宜 内存和CPU时间只会变得越来越快,越来越便宜,所以无论你认为什么是性能损失"今天看起来明显是一个微不足道的抱怨,而不是让你的昂贵的程序员在将来跟踪代码中的愚蠢速度黑客的实际成本。

(如果你的程序员并不比你的计算资源贵得多你为什么雇用这些可怕的程序员?!?!?ZOMG!

关于未来的说明......

未来只会越来越多核,并且在大多数情况下,更多并行更多并发。现在AMD正在执行其将1000多个核心系统带到桌面的愿景,我预测下一个重大争议将是总线速度,通道,缓存管理以及核心内存大小的大幅增加。这是所有这些核心就业的唯一途径。

唯一能够利用它的语言将是像Erlang那样实现按值传递消息作为主要方法的语言,由大型二进制引用传递和全局堆对象的显式复制等混合情况支持。在这种世界中,卫生范式将变得更加重要,语言简单将成为拯救我们免受并行性和并发性所带来的复杂性爆炸的元素。

考虑推动微服务架构"甚至是Docker--人们无意识地磕磕绊绊,然后解决了Erlang最初设计解决的许多相同问题,只是以特别的方式解决。

在大规模多核,大规模并发环境中,按值传递并且每个进程具有堆似乎是一个整体优化,考虑到与核心,主轴,存储和记忆。 (顺便说一下,我认为将来会有更少的程序员使用并发语言中更持久的软件,而猴子军队的方法将继续产生基本上短暂的代码库。)