究竟是什么让 Erlang 进程、绿色线程、协程"lighter"比内核线程?繁重的上下文切换呢?



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

每当提到Erlang进程、绿色线程或协同程序时,与内核线程相比,它们总是被描述为"轻量级"。通常给出的原因是内核线程涉及上下文切换,这很慢。

但是,缓慢的上下文切换究竟是怎么回事呢?与在userland中切换绿色线程相比,它慢了多少?

上下文切换是导致事件驱动程序(如Nignx(和多处理程序(如Apache(之间性能和内存消耗差异的主要(唯一?(因素吗?

抢占式、单片式、多任务操作系统上的上下文切换涉及两种路径之一,要么通过某种系统服务调用(睡眠、互斥获取、等待事件、阻塞I/O(向调度程序隐式屈服,要么通过中断和调度程序决定交换正在运行的任务。

当调度程序交换任务时,会发生一些重量级的事情:

  • 所有操作都作为操作系统内核的一部分,以高权限运行。每个操作都会被检查(或者应该检查(,以确保调度程序所做的决定不会授予任务任何额外的权限(想想本地根漏洞(
  • 交换用户模式进程地址空间。这导致内存管理器在页面表布局上游刃有余,并将新的目录基加载到控制寄存器中
  • 这也意味着保留在CPU缓存中的数据可能会被删除和清除。如果你的任务刚刚访问了一堆常用的东西,然后上下文切换并"丢失"了它(下次访问时,它可能不得不再次从主存中提取(,那就太糟糕了
  • 根据捕获内核的方式,然后需要捕获内核的OUT。例如,如果您进行系统调用,CPU将经过一组非常精确的步骤来转换到内核中运行的代码,然后在退出时展开这些步骤。这些步骤比对程序中的另一个模块进行函数调用更复杂,因此需要更多的时间

据我所知,绿色线程任务非常简单。用户模式调度器指示协同程序运行,直到协同程序产生结果。上面的几个区别:

  • 协同程序的调度都不是在内核模式下进行的,事实上,调度绿色线程通常不需要涉及任何操作系统服务或任何阻塞的操作系统服务。因此,所有这些都可以在没有任何上下文切换或任何用户/内核转换的情况下实现
  • 绿色线程不是预先调度的,甚至根本没有被绿色线程管理器预先调度,而是协同调度的。这有好有坏,但有写得好的例程,总体来说是好的。每个任务都精确地完成它需要做的事情,然后陷阱返回到调度器,但没有任何上下文交换开销
  • 绿色线程共享它们的地址空间(据我所知(。上下文开关上不会发生地址空间的交换。堆栈是交换的(据我所知(,但这些堆栈是由调度器管理的,交换堆栈也只是简单地写入寄存器。交换堆栈也是一种非私有操作

简而言之,用户模式下的上下文切换包括一些库调用和对堆栈指针寄存器的写入。内核模式下的上下文切换涉及中断、用户/内核转换以及系统级行为,如地址空间状态更改和缓存刷新。

最新更新