标签:
文中所有的Proactor模式,均指模拟Proactor模式,而不是操作系统级别的Proactor
先说下Erlang的check_io是做什么用的。Erlang中的check_io实质是调用系统的epoll/select/kevent/poll对IO事件进行检查。
那么问题就产生了,Erlang的网络模型不是Proactor模式嘛,它和scheduler有什么关系?
为了回答这个问题,我们先说下Erlang的Proactor模式和常规的Proactor模式有什么样的差异。
Erlang所采用Proactor模式和常规的Proactor模式相比有两大差异。第一大差异是,Erlang的Proactor模式并没有专用的IO线程,而是复用scheduler的线程。第二大差异是,Erlang的Proactor模式并没有在事件发生后立刻进行IO读写操作,而是将读写操作的事件放入和fd相关联的Erlang驱动中了,由Erlang的驱动来完成真正的IO操作。这样我们就能很明显的看出来,Erlang的scheduler既是IO线程又是业务线程。
好了,这又产生问题了,Erlang为什么选择这样做?那么Erlang是如何让scheduler线程平衡IO操作和业务处理的?
Erlang这么做我个人认为有以下几个原因:
常规Proactor模式中,IO操作集中在IO线程上面,当其中一个Socket传输大块数据的时候,会出现IO时效性降低。因为Erlang的网络驱动本身是一个Port进程,而多个Port进程可以分散到多个Erlang的schduler中,如果将事件和fd放入驱动的队列当中,让驱动来完成真正的IO操作,将读写IO的操作分散到多个线程上,会大大的提高IO的时效性。
作为一个通用语言的虚拟机,Erlang不能假设某种业务场景针对Proactor模式进行优化。当出现业务并不复杂而IO吞吐又很高的情况时,会出现业务线程大量空闲而IO线程满载的场景,那么这也是一种资源浪费,所以让业务线程参与到部分IO操作上可以提高IO吞吐的量级。
Erlang是如何让scheduler线程平衡IO操作和业务处理的:
Erlang的scheduler使用优先执行RunQueue中任务然后在进行IO检查的策略。
Erlang的scheduler中有一个计数器,当RunQueue的任务执行到一定数量的时候,强制性的进行IO检查,防止过度执行RunQueue而让IO没机会进行检查。
多个scheduler共享一个pollset,当一个scheduler检查IO的时候,其它scheduler尽最大力量执行RunQueue。这里面通过使用原子性的置位操作,减少了多个scheduler去抢锁引起的开销。
标签:
原文地址:http://my.oschina.net/u/236698/blog/380289