目录
本文概览:介绍内核的五种IO模型。
- 实现:相比阻塞IO,IO多路复用也是使用recvfeom接受数据,IO复用在第一个阶段通过select代替了阻塞I/O的循环检查。
- 功能:I/O多路复用是用于提升效率,单个进程可以同时监听多个网络连接IO,即在I/O复用模式下在第一个阶段大量的连接统统都可以过来直接注册到Selector复用器上面,同时只要单个或者少量的线程来循环处理这些连接事件就可以了;而 阻塞式I/O如果要接收更多的连接,就必须创建更多的线程。
Q: IO多路复用和信号驱动区别
A: 都包含两个阶段,第一个阶段select是复用是阻塞的; 信号驱动在第一个阶段是非阻塞的。
Q: 信号驱动和异步IO
A: 异步IO只包含一个阶段,而且非阻塞。 信号驱动包含sigaction和recvfrom两个阶段,第二个阶段是阻塞的。
1 内核IO模型介绍
IO模型主要包含如下两步,五种IO也是基于这两步进行优化:
- 调用内核函数,内核准备数据;
- 内核准备完成数据之后,把内核数据拷贝到程序进程空间。
常见的有五种IO模型:阻塞IO(BIO)、、非阻塞IO、IO复用(Java nio使用这种模型)、信号驱动IO、异步IO,前四种都是同步IO模型。五种模型演进的意义都是为了减少占用CPU时间,提供内核系统高并发的能力,即让CPU做更多的事情。这五种模型,都是应用程序通过调用内核相关接口函数来实现。
2 BIO-阻塞IO
3 NIO-非阻塞IO
NIO(Non-blocking I/O),它是一种同步非阻塞的I/O模型,也是I/O多路复用的基础。这里NIO不是指Java领域中的New I/O。NIO和BIO的区别,前者是非阻塞的,立刻返回结果,后者会一直阻塞。
NIO相对于BIO优点有:
- 在内核准备数据阶段,节省了CPU,不需要一直占用CPU,只是通过应用程序反复查看。
4 IO多路复用
4.1 介绍
1、介绍
I/O多路复用就是通过一个进程可以监视多个描述符,一旦某个描述符就绪,就通知应用程序进行相应的读写操作。目前常用的有 select、poll、 epoll三种实现方式, 。
2、IO多路复用与NIO比较
(1)不同
- 对于NIO(Not Blocking IO),需要程序代码循环轮询调用recvFrom内核接口来查看数据是否准备完毕。
- 对于IO多路复用,只需要在代码中调用一次Select、poll、或者epoll内核接口,轮询操作由这个内核函数来完成,不再需要像NIO那样,通过程序app自己去轮询调用内核接口来查询。
(2)IO多路复用相对于NIO优点
- 不需要应用程序去反复查看内核是否准备数据,解放了CPU
4.2 select
1、函数
当存在返回值时,就说明有文件描述符已经准备就绪。此时可以通过遍历队列方式获取准备就绪的文件描述符t。
1 |
int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); |
- 监控的描述符个数有最大限制
4.3 poll
1、机制
select和poll都需要在返回就绪后,通过遍历文件描述符来获取已经就绪的socket。
2、poll和select比较
没有最大限制,通过列表链表实现。
3、缺点
和select一样,当存在很多客户端连接,但是只有很少的处于就绪状态, 此时随着监视的描述符数量的增长,其效率也会线性下降。
4、内核函数
1 |
int poll (struct pollfd *fds, unsigned int nfds, int timeout); |
4.4 epoll
1、机制
select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。综上,select/poll/epoll在被唤醒时,select和poll扫描整个文件符队列获取到“准备好数据”的节点,epoll简化了这种查找,提供了一个队列来保存准备好数据的节点。
2、优点
如果没有大量的idle -connection或者dead-connection,epoll的效率并不会比select/poll高很多,但是当遇到大量的idle- connection,就会发现epoll的效率大大高于select/poll。
3、三个函数
1 2 3 4 5 |
int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); |
5 信号驱动IO
内核在描述符就绪时,发送SIGIO信号通知应用进程,在等待数据期间,应用进程不阻塞。
6 AIO-异步IO
1、AIO介绍
AIO(Asynchronous I/O)异步 I/O ,告知内核启动某一个操作,并让内核在整个操作(包括将数据从内核复制到我们自己的缓冲区)完成后通知应用进程。
2、与信号驱动IO的比较
信号驱动IO是由内核通知应用进程核实可以启动一个I/O操作,而异步IO是内核通知我们IO操作何时完成。
3、AIO相比于NIO的优点
AIO把“内核拷贝数据到应用程序” 这个阶段的时间也变成了不阻塞,释放了CPU
附: 两个概念
1、同步与异步
通信机制
2、阻塞和非阻塞
这个是进程级别的属性
参考文献
1、《UNIX 网络编程 卷1;套接字联网API 》6.2 节 IO模型