从erlang R12B版本开始,启动erl时系统自动检测CPU内核数,并启动相同数量的scheduler,也可以通过erl +S Number来设置,不过启动比CPU核数更多的调度器不会提高性能,启动erl时开启或关闭SMP(Symmetrical Multi Processor) -smp enable -smp disable
[smp:4:4],其中第一个4表示当前的调度器数量,第二个4表示CPU核数
Erlang通常在机器上的每一个处理器核心上跑一个线程。每一个线程运行一个调度器。这种设定是为了确保机器上所有的核心都可以为Erlang系统卖力
1). 进程调度运行在用户空间 :Erlang进程不同于操作系统进程,Erlang的进程调度也跟操作系统完全没有关系,是由Erlang虚拟机来完成的;
2). 调度是抢占式的:每一个进程在创建时,都会分配一个固定数目的reduction(默认值是2000),每一次操作(函数调用),reduction就会减少,当这个数量减少到0时或者进程没有匹配的消息时,抢占就会发生(无视优先级);
3). 每个进程公平的使用CPU:每个进程分配相同数量的reduction,可以保证进程可以公平的(不是相等的)使用CPU资源
4). 调度器保证软实时性:Erlang中的进程有优先级,调度器可以保证在下一次调度发生时,高优先级的进程可以优先得到执行。Erlang进程有四种优先级:max, high, normal, low(max只在Erlang运行时系统内部使用,普通进程不能使用)。
5)准确地说,抢占(preemption)[2]指的是调度器能够强制剥夺任务的执行。所有基于协作(cooperation)的多任务都是做不到抢占的,例如Python的twisted库、Node.js和LWT(Ocaml)等。但是更有意思的是,Go(golang.org)和Haskell(GHC)也都不是完全抢占式的。Go只有在通信的时候会发生上下文切换,因此一个密集的循环就会霸占整个处理器核心
为什么要小心耗时长的NIF的原因。NIF默认不会被抢占,而且也不会贡献reduction计数器。因此耗时长的NIF会引入系统延迟。
对于可以并发执行的server,可以通过两种方式来提供并发和负载
方式1:多开几个进程池,通过某个规则来把任务分发到各个server上。
方式2: 多开几个进程池,并且开一个管理进程,每次有任务来请求管理进程,管理进程把具体任务分配到当前空闲的进程池。
方式1可能会出现这种情况
某个时刻 可能任务分配不均匀,只用到了一个进程
方式2的有点这样做的优点是可以真正做到负载均衡,并且可以动态的增加进程数来提高负载。
开多少个进程来负载:
1):cpu密集型
可以通过erlang:system_info(schedulers) 获得cpu 核心数,
可以开等于cpu核心数或者略大于cpu核心数的进程。
2):io密集型
大于cpu核心数