从技术上讲,为什么Erlang中的进程比OS线程更高效?

6qftjkof  于 2022-12-08  发布在  Erlang
关注(0)|答案(7)|浏览(202)

Erlang的特性
(2009年)
Erlang并发是快速和可伸缩的。它的进程是轻量级的,因为Erlang虚拟机并不为每个创建的进程创建一个操作系统线程。它们在VM中创建、调度和处理,独立于底层操作系统。因此,进程创建时间是微秒级的,并且独立于并发存在的进程的数量。与Java和C#相比,其中为每个进程创建一个底层OS线程:您将得到一些非常有竞争力的比较结果,Erlang的表现远远超过这两种语言。
来自Concurrency oriented programming in Erlang (pdf)(slides)(2003年):
我们观察到,在2,500个过程中,产生一个厄兰过程所需的时间是恒定的1微秒;此后,对于多达30,000个进程,它会增加到大约3µs。Java和C#的性能显示在图的顶部。对于少量进程,创建一个进程需要大约300µs。创建超过2000个进程是不可能的。
我们可以看到,对于多达30,000个进程,在两个Erlang进程之间发送一条消息的时间大约为0.8µs。对于C#,每条消息大约需要50µs,这是进程的最大数量(大约有1800个进程)。Java甚至更糟,对于多达100个进程,每个消息大约需要50µs,此后,当有大约1000个Java进程时,它迅速增加到每个消息10 ms。
我的想法
从技术上讲,我不完全理解为什么Erlang进程在生成新进程时效率更高,并且每个进程的内存占用量更小。操作系统和Erlang VM都必须进行调度、上下文切换,并跟踪寄存器中的值等等...
简单地说,为什么操作系统线程的实现方式与Erlang中的进程不同?它们必须支持更多的东西吗?为什么它们需要更大的内存占用?为什么它们的繁殖和通信速度较慢?
从技术上讲,为什么Erlang中的进程在繁殖和通信方面比操作系统线程更高效?为什么操作系统中的线程不能以同样高效的方式实现和管理?为什么操作系统线程有更大的内存占用,加上更慢的繁殖和通信?

更多阅读

  • 第1193章:一个人的未来(2008)
  • 第1133章:一个人的未来(2004)
  • 第1198章:一个人的幸福
deikduxw

deikduxw1#

因为Erlang解释器只需要担心它自己,所以操作系统还有很多其他的事情要担心。

blmhpbnm

blmhpbnm2#

其中一个原因是Erlang进程不是在OS中创建的,而是在EVM(Erlang虚拟机)中创建的,因此开销较小。

mw3dktmi

mw3dktmi3#

有几个影响因素:

  1. Erlang进程不是操作系统进程,它们是由ErlangVM使用轻量级协作线程模型实现的(在Erlang级别抢占,但在协作调度运行时的控制下)。这意味着切换上下文要便宜得多,因为它们只在已知的受控点切换,因此不必保存整个CPU状态(正常、SSE和FPU寄存器、地址空间Map等)。
  2. Erlang进程使用动态分配的堆栈,堆栈开始时很小,然后根据需要增长。这允许在不占用所有可用RAM的情况下产生成千上万--甚至数百万--的Erlang进程。
  3. Erlang曾经是单线程的,这意味着没有确保进程间线程安全的要求。它现在支持SMP,但在同一调度器/内核上的Erlang进程间的交互仍然是非常轻量级的(每个内核都有单独的运行队列)。
pprl5pva

pprl5pva4#

经过进一步的研究,我找到了乔·阿姆斯特朗的一份报告。
Erlang - software for a concurrent world (presentation)开始(13分钟时):
[Erlang] is a concurrent language – by that I mean that threads are part of the programming language, they do not belong to the operating system. That's really what's wrong with programming languages like Java and C++. It's threads aren't in the programming language, threads are something in the operating system – and they inherit all the problems that they have in the operating system. One of the problems is granularity of the memory management system.操作系统中的内存管理会保护整个内存页面,因此线程的最小大小可以是页面的最小大小。That's actually too big.
If you add more memory to your machine – you have the same number of bits that protects the memory so the granularity of the page tables goes up-对于一个运行在几百字节内的进程,您最终会使用64 kB。
我想它回答了我的一些问题,如果不是全部的话

anhgbhbe

anhgbhbe5#

我在汇编程序中实现了协程,并测量了性能。
在协程(也叫Erlang进程)之间切换,在现代处理器上大约需要16条指令和20纳秒。而且,您通常知道要切换到的进程(例如:在其队列中接收消息的进程可以被实现为从调用进程到接收进程的直接切换),因此调度器不起作用,使其成为O(1)操作。
如果你有成千上万甚至上百万个线程,那么你需要花费O(log(n))或O(log(log(n)))的时间来运行操作系统线程调度程序。
因此,Erlang进程速度更快,伸缩性更好,因为切换的基本操作速度更快,调度程序的运行频率更低。

rvpgvaaj

rvpgvaaj6#

Erlang进程(近似)对应于其他语言中的green threads;在进程之间没有操作系统强制的分离。(很可能有语言强制的分离,但是尽管Erlang做得比大多数更好,但这是一个较低的保护。)因为它们的重量轻得多,所以它们可以被更广泛地使用。
另一方面,操作系统线程可以简单地在不同的CPU内核上调度,并且(大部分)能够支持独立的CPU绑定处理。操作系统进程类似于操作系统线程,但具有更强的操作系统强制分离。这些功能的代价是操作系统线程和(甚至更多)进程的成本更高。
另一种理解不同之处的方法是这样的:假设你要在JVM上编写一个Erlang的实现(这不是一个特别疯狂的建议),那么你会让每个Erlang进程成为一个具有某种状态的对象。这是运行Erlang进程的真实Erlang运行时中的一个可调参数。反过来,这将把要完成的工作分配到可用的真实系统资源中。这是一种非常简洁的做事方式,但 * 完全 * 依赖于每个单独的Erlang进程并不做很多事情的事实。当然,这没关系; Erlang的结构不要求这些单独的进程是重量级的,因为它是执行程序的整体。
在很多方面,真实的的问题是术语的问题。(并且与CSP、CCS,特别是π演算中的相同概念有很强的对应关系)与继承了C语言的语言完全不同。(包括C++、Java、C#、和许多其他函数)调用进程或线程。(所有这些都涉及到并发执行的概念),但肯定没有等价性。他们可能会理解成完全不同的意思。

u2nhd7ah

u2nhd7ah7#

我想Jonas想要一些比较OS线程和Erlang进程的数据。不久前,我测试了从Erlang进程到OS线程的可伸缩性。(因为Apache使用操作系统线程)。有一个旧网站的数据可以追溯到1998年。我只找到了一次这个网站。所以我不能提供链接。但信息是在那里。这项研究的主要观点表明,Apache的最大进程数略低于8K,而他手写的Erlang服务器处理的进程数超过10K。

相关问题