Nginx和Apache都是Web服务器。Nginx能抗住几万的高并发,而Apache却只能几千。主要的原因在于IO多路复用的选择。
白话版:
专业版:
我们先来理解什么是用户态和内存态:
内核态:
CPU可以访问内存所有数据, 包括外围设备, 例如硬盘, 网卡. CPU也可以将自己从一个程序切换到另一个程序
用户态:
只能受限的访问内存, 且不允许访问外围设备. 占用CPU的能力被剥夺, CPU资源可以被其他程序获取
为什么要有用户态和内核态:
由于需要限制不同的程序之间的访问能力, 防止他们获取别的程序的内存数据, 或者获取外围设备的数据, 并发送到网络, CPU划分出两个权限等级 -- 用户态 和 内核态
selec缺点:
- 每次调用select都需要把fd从用户态拷贝到内核态,开销比较大
- 每次都需要在内核遍历传入的fd
- select支持文件数量比较小,默认是1024
epoll:
select/poll只提供了一个函数,select/poll函数。但epoll一下子就提供了3个函数。
epoll_create:创建一个epoll句柄
epoll_ctl:注册要监听的事件类型
epoll_wati:等待事件产生
epoll优点:
- 每次注册新事件到epoll句柄都会把所有的fd拷贝进来,而不是在epoll_wait中重复拷贝,这样保证fd只会被拷贝一次
- epoll不是像select/poll那样每次都把fd加入等待队列,epoll为每个fd指定一个回调函数,当设备就绪时,唤醒等待队列的等待者就会调用他的回调函数,这个回调函数会把就绪的fd加入一个就绪链表,epoll_wait就是在这个就绪链表中查看有没有就绪fd
- epoll没有fd数目限制
总结:
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用 epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在 epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的 时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要 一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内 部定义的等待队列)。这也能节省不少的开销。
专业版来源:https://yq.aliyun.com/articles/48668
站在巨人的肩膀上成长,文章思想和经验来自网络上的大神,未能一一列举,在此,谢过不杀之恩。