Rust 和Erlang的对比(5)

并发在Rust中如何工作?当您使用本机操作系统线程时,它们是由操作系统调度程序调度的。当您使用本机操作系统线程时,它们将由操作系统调度程序调度。例如,如果在Linux下,调度效率随着线程数量而下降。但是,Erlang的BEAM从一个本地操作系统线程中分离出并管理多个绿色线程。在默认情况下,每个进程被指定2000衰减(erlang中的每个操作都有一个衰减预算,其中1衰减大致相当于一个最小函数调用),直到分配的衰减额耗尽前都允许运行,随后抢占为止。抢占时,运行队列中的下一个Erlang进程将被安排运行。这就是每个Erlang进程的调度方式。

BEAM层是如何进行内存管理的?正如我们所提到的,每个本地操作系统线程的堆在多个Erlang进程之间共享。无论何时Erlang进程需要更多内存,它都会在本地操作系统线程堆中查找可用内存并拿到它(如果可用)。否则,根据请求的数据类型,特定的内存分配器服务会尝试使用malloc或mmap从OS获取一块内存。BEAM通过将内存块划分为多个载体块(由分配器管理的内存块的容器)和每个Erlang进程与正确的载体一起提供,从而在多个进程中有效利用了这块内存。根据当前的需要,如从网络套接字中读取大量XML节,BEAM会动态地计算出应该分配多少内存,分配内存的载体数量,GC周期释放之后保持多少载体等等。释放的内存块几乎在重新分配后就会立即合并,这样下一次分配就会更快了。

Erlang垃圾收集如何工作?Erlang提供了一个每进程垃圾回收器,它使用分代标记清除垃圾回收算法。与Erlang内置的不分享方式想配合,收集一个进程的垃圾不会以任何方式干扰其他进程。每个进程都有一个年轻的堆和一个旧堆。年轻堆的垃圾收集更频繁。如果有些数据在两个连续的年轻垃圾回收周期中存活,它将被移至旧堆。只有在达到指定大小后,旧堆才会被垃圾回收处理。 

Erlang的容错是如何工作的?Erlang认为失败是不可避免的,它试图做好处理准备。任何普通的Erlang应用程序都需要遵循一个监督层级,在这个层级中,每个Erlang进程都需要一位监督者予以监督。监督者负责根据故障类型重新启动其控制下的工作进程。监督者还可以根据工作人员监控的类型对工作人员配置重启策略,例如一对一(每个工作进程退出仅关系到一个工作进程),一对多(如果一个工作进程退出,则重新启动所有工作进程)等。BEAM提供链接以在进程之间传播退出信号,以及监视器以监视在相同BEAM VM内的进程之间传播的退出信号,并且还可以跨越分布式的BEAM Vm透明地传递位置。Erlang的BEAM还可以一次在一个虚拟机或所有虚拟机上动态加载代码。BEAM负责加载内存中的代码变更并应用它们。告诉BEAM有关加载模块的顺序、状态管理等所需的额外努力,以防止任何未确定的进程状态。

与Erlang相反,Rust在编译程序时完成了大部分工作,而在运行时只做了很少的工作。由于大多数系统编程语言在运行时缺乏内存安全性,因此Rust会尽力确保代码编译完成后在运行时没有问题。虽然BEAM以运行时确保内存安全,但有时开销会变得异常复杂,所以Rust选择在编译时。

Rust的核心语言特性就是旨在尽可能简洁。举个例子:Rust常常在晚上构建具有轻量级的绿色线程(类似于Erlang进程)。在某一时刻,该特性被有意识地删除了,因为它不被视为每个应用程序的通用需求,并且它伴随着一定的运行时成本。相反,该特性可以在需要时通过crate提供。虽然Erlang也可以导入外部库,但其核心功能(如绿色线程)嵌入到VM中了,不能关闭或使用本地线程进行交换。尽管如此,Erlang Vm的绿色线程效率非常高,近几十年早已证明了这一点,关闭它对于选择使用Erlang的人来说不是一个常见的要求。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/97c0db980c0ffb0e8e85ab46f9cbb20f.html