对于第三个缺点:epoll没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,一般来说这个数目和系统内存关系很大
epoll的高性能
epoll使用了红黑树来保存需要监听的文件描述符事件,epoll_ctl增删改操作快速
epoll不需要遍历就能获取就绪fd,直接返回就绪链表即可
linux2.6 之后使用了mmap技术,数据不在需要从内核复制到用户空间,零拷贝
关于epoll的IO模型是同步异步的疑问概念定义
同步I/O操作:导致请求进程阻塞,直到I/O操作完成
异步I/O操作:不导致请求进程阻塞,异步只用处理I/O操作完成后的通知,并不主动读写数据,由系统内核完成数据的读写
阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待
异步IO的概念是要求无阻塞I/O调用。前面有介绍到I/O操作分两阶段:R1等待数据准备好。R2从内核到进程拷贝数据。虽然epoll在2.6内核之后采用mmap机制,使得其在R2阶段不需要复制,但是它在R1还是阻塞的。因此归类到同步IO
Reactor模型Reactor的中心思想是将所有要处理的I/O事件注册到一个中心I/O多路复用器上,同时主线程/进程阻塞在多路复用器上;一旦有I/O事件到来或是准备就绪,多路复用器返回,并将事先注册的相应I/O事件分发到对应的处理器中
相关概念介绍:事件:就是状态;比如:读就绪事件指的是我们可以从内核读取数据的状态
事件分离器:一般会把事件的等待发生交给epoll、select;而事件的到来是随机,异步的,所以需要循环调用epoll,在框架里对应封装起来的模块就是事件分离器(简单理解为对epoll封装)
事件处理器:事件发生后需要进程或线程去处理,这个处理者就是事件处理器,一般和事件分离器是不同的线程
Reactor的一般流程1)应用程序在事件分离器注册读写就绪事件和读写就绪事件处理器
2)事件分离器等待读写就绪事件发生
3)读写就绪事件发生,激活事件分离器,分离器调用读写就绪事件处理器
4)事件处理器先从内核把数据读取到用户空间,然后再处理数据
1)应用程序在事件分离器注册读完成事件和读完成事件处理器,并向系统发出异步读请求
2)事件分离器等待读事件的完成
3)在分离器等待过程中,系统利用并行的内核线程执行实际的读操作,并将数据复制进程缓冲区,最后通知事件分离器读完成到来
4)事件分离器监听到读完成事件,激活读完成事件的处理器
5)读完成事件处理器直接处理用户进程缓冲区中的数据
Proactor是基于异步I/O的概念,而Reactor一般则是基于多路复用I/O的概念
Proactor不需要把数据从内核复制到用户空间,这步由系统完成
欢迎指正文中错误 参考文章聊聊Linux 五种IO模型
网络io模型
网络IO
5种网络IO模型
epoll原理详解及epoll反应堆模型