Erlang 以支援多个轻量级进程而闻名;它能够做到这一点,是因为这些进程不是传统意义上的进程,甚至不像 P-threads 中的线程那样,而是完全在用户空间中的线程。
这很好(实际上非常棒)。但是,在多核/多处理器环境下,Erlang 线程如何并行执行呢?它们肯定必须以某种方式映射到内核线程才能在单独的核心上执行,对吗?
假设确实是这样,那么这是如何完成的?许多轻量级进程被映射到一个内核线程吗?
还是有其他解决方法?
Erlang 以支援多个轻量级进程而闻名;它能够做到这一点,是因为这些进程不是传统意义上的进程,甚至不像 P-threads 中的线程那样,而是完全在用户空间中的线程。
这很好(实际上非常棒)。但是,在多核/多处理器环境下,Erlang 线程如何并行执行呢?它们肯定必须以某种方式映射到内核线程才能在单独的核心上执行,对吗?
假设确实是这样,那么这是如何完成的?许多轻量级进程被映射到一个内核线程吗?
还是有其他解决方法?
答案取决于使用的虚拟机:
1) 非SMP: 有一个调度程序(操作系统线程),它执行来自可运行进程池(即那些没有被例如receive
阻塞的进程)的所有Erlang进程。
2) SMP: 有K个调度程序(操作系统线程,K通常是CPU核心数),从共享进程队列中执行Erlang进程。它是一个简单的FIFO队列(通过锁允许多个操作系统线程同时访问)。
3) R13B及更高版本的SMP:将会有K个调度程序(与之前一样),它们从多个进程队列中执行Erlang进程。每个调度程序都有自己的队列,因此将添加进程迁移逻辑,以便从一个调度程序迁移到另一个调度程序。这种解决方案通过避免在共享进程队列中过多地锁定来提高性能。
有关更多信息,请参见由肯尼斯·伦丁(Kenneth Lundin)、爱立信公司为Erlang用户大会(2008年11月13日,斯德哥尔摩)准备的此文档。
我想修正之前的答案。
Erlang, 或者说 Erlang 运行时系统(erts),默认将调度器数量(操作系统线程)和运行队列数量设置为您平台上的处理元素数量。这是处理器核心或硬件线程数。您可以使用以下方法在运行时更改这些设置:
erlang:system_flag(schedulers_online, NP) -> PrevNP
Erlang进程目前没有与任何调度程序相关联。将进程在调度器之间平衡的逻辑遵循两个规则:1)饥饿的调度器会从另一个调度器中夺取工作。2)建立迁移路径,将进程从具有大量进程的调度器推送到具有较少工作量的调度器。这样做是为了确保每个进程的减少计数(执行时间)公平。
但是调度程序可以锁定到特定的处理元素上。默认情况下不会执行此操作。要让erts执行调度程序->核心关联,请使用:
erlang:system_flag(scheduler_bind_type, default_bind) -> PrevBind
文档中还可以找到其他绑定类型。使用亲和力可以在高负载情况下大大提高性能!尤其是在高锁争用情况下。此外,至少可以说,Linux内核无法处理超线程。如果您的平台有超线程,您应该真正使用Erlang中的此功能。
我推荐Jesper Louis Andersen在这个主题上的一篇博客文章http://jlouisramblings.blogspot.com/2013/01/how-erlang-does-scheduling.html
简而言之,Erlang进程不是操作系统线程,并且不能直接映射到它们。Erlang调度器是在操作系统线程上运行的,提供了更细粒度的Erlang进程的智能实现,将这些细节隐藏在程序员眼中。