2019独角兽企业重金招聘Python工程师标准>>>
Erlang调度器主要完成对Erlang进程的调度,它是Erlang实现软件实时和进程之间公平使用CPU的关键。Erlang运行时,有4种任务需要被调度:进程,Port,Linked-in driver,Erlang虚拟机的系统级活动。
Erlang调度器主要有以下特点:
1. 进程调度运行在用户空间 :Erlang进程不同于操作系统进程,Erlang的进程调度也跟操作系统完全没有关系,是由Erlang虚拟机来完成的;
2. 调度是抢占式的:每一个进程在创建时,都会分配一个固定数目的reduction(R15B中,这个数量默认值是2000),每一次操作(函数调用),reduction就会减少,当这个数量减少到0时或者进程没有匹配的消息时,抢占就会发生(无视优先级);
3. 每个进程公平的使用CPU:每个进程分配相同数量的reduction,可以保证进程可以公平的(不是相等的)使用CPU资源
4. 调度器保证软实时性:Erlang中的进程有优先级,调度器可以保证在下一次调度发生时,高优先级的进程可以优先得到执行。
Reduction
受操作系统中基于时间片调度算法的影响,一开始知道有reduction这个概念时,一直想搞清楚这个reduction到底对应多长的绝对时间,不过,从Erlang本身对reduction的使用来看,完全没有必要纠结这个问题。《Erlang编程指南》一书中对reduction的说明如下:
程序中的每一个命令,无论它是一个函数调用,还是一个算术操作,或者内置
函数,都会分配一定数量的reduction。虚拟机使用这个值来衡量一个进程的活
动水平。
看到这个定义的第一反应是,如果一个函数调用的执行时间很长怎么办?那不是一个进程会长时间的占用资源?Erlang对这个问题的答案是Trap机制,上一篇中有提到过,它的其中一个功能就是把费时的操作分阶段做,比如lists:reverser和lists:member可能会根据输入的不同会有很大的变化,所以就会使用到Trap机制:先执行一段时间,再Trap,然后再次调度到的时候再继续执行。
SMP支持
从R11B(2006)Erlang开始支持SMP(Symmetrical Multi Processor,也就是多核)。Erlang对SMP的支持分为以下几个阶段:
1). 单调度器、单运行队列:调度器运行在虚拟机主进程中的一个线程中,从单个任务队列中获取运行进程,因为只有一个线程,所以对运行队列的访问不需要锁;
2). 多调度器、单运行队列:调度器的个数可以自定义(参见erl命令的+S参数,默认数量同CPU核的数量),每个调度器运行在一个线程中,但是只有一个运行队列,所有调度器都从同一个运行队列获取运行进程,所以会涉及到共享资源的访问,需要用到锁。
3). 多调度器、多运行队列:每个调度器都绑定有一个运行队列,每个调度器都从各自的运行队列中获取运行进程。相比单运行队列,多运行队列会减少锁冲突,提高性能,但是,因为涉及到多运行队列,就必需要考虑负载问题:如果一个调度器很忙,另一个很闲,那怎么办?Erlang虚拟机存在一个任务迁移的逻辑,来保证各个调度器达到平衡。
进程优先级
Erlang进程有四种优先级:max, high, normal, low(max只在Erlang运行时系统内部使用,普通进程不能使用)。Erlang运行时有两个运行队列对应着max和high优先级的运行任务,normal和low在同一个队列中。
调度器在调度发生时,总是首先查看具体max优先级的进程队列,如果队列中有可以进行的进程,就会运行,直到这个队列为空。然后会对high优先级的进程队列做同样的操作(在SMP环境,因为同时有几个调度器,所以在同一时间,可能会有不同优先级的任务在同时运行;但在同一个调度器中,同一时间,肯定是高优先级的任务优先运行)。
普通进程在创建时,一般是normal优先级。normal和low优先级的进程只有在系统中没有max和high优先级的进程可运行时才会被调度到。通常情况下,normal和low优先级的进程交替执行,low优先级获得CPU资源相对更少(一般情况下):low优先级的任务只有在运行了normal优先级任务特定次数后(在R15B中,这个数字是8)才会被调度到(也就是说只有在调度了8个normal优先级的进程后,low优先级的进程才会被调度到,即使low优先级的进程比normal优先级的进程更早进入调度队列,这种机制可能会引起优先级反转:假如你有成千上万的活动normal进程,而只有几个low优先级进程,那么相比normal进程,low优先级可能会获得更多的CPU资源)。
调度算法的实现见[$OTP_SRC/erts/emulator/beam/erl_process.c --> schedule],下面的图片是算法流程图,来源于这篇论文:Characterizing the Scalability of Erlang VM on Many-core Processors。