IO从概念上来说,总共有5种:
(1)阻塞IO (blocking I/O)
(2)非阻塞IO (nonblocking I/O)
(3)IO多路复用 (I/O multiplexing (select and poll))
(4)事件驱动IO (signal driven I/O (SIGIO))(Unix)
(5)异步IO (asynchronous I/O (the POSIX aio_functions))
不管文件IO还是网络socket的IO,其读写都需要经过两个阶段:
(1) wait for data(准备数据到内核的缓冲区)
(2) copy data from kernel to user (从内核缓冲区拷贝到用户空间)
阻塞 IO(blocking IO)
在 linux 中,默认情况下所有的 socket 都是 blocking。
blocking IO 的特点就是在 IO 执行的两个阶段(等待数据和拷贝数据两个阶段)都被 block 了。
非阻塞 IO(non-blocking IO)
Linux 下,可以通过设置 socket 使其变为 non-blocking。当对一个 non-blocking socket 执行读操作时,流程是这个样子
从图中可以看出,当用户进程发出 read 操作时,如果 kernel 中的数据还没有准备好,那 么它并不会 block 用户进程,而是立刻返回一个 error。
从用户进程角度讲 ,它发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果。
使用非阻塞的接收方式,服务器线程可以通过循环调用 recv()接口,可以在单个线程内实现对所有连接的数据接收工作。但是上述模型绝不被推荐。因为循环调用 recv()将大幅度推高 CPU 占用率
;此外,在这个方案中 recv()更多的是起到检测“操作是否完成”的作用,实际上操作系统提供了更为高效的检测“操作是否完成“作用的接口,例如 select()多路复用模式, 可以一次检测多个连接是否活跃。
IO多路复用(IO multiplexing)
IO multiplexing 即多路复用IO,select/poll/epoll就是属于此种类型。有些地方 也称这种 IO 方式为事件驱动 IO(event driven IO)(Unix系统下)
poll和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。
epoll 通过两个方面,很好解决了 select/poll 的问题。 第一点,epoll 在内核里使用红黑树来跟踪进程所有待检测的文件描述字,把需要监控的 socket 通过 epoll_ctl() 函数加入内核中的红黑树里,红黑树是个高效的数据结构,增删查一般时间复杂度是 O(logn),通过对这棵黑红树进行操作,这样就不需要像 select/poll 每次操作时都传入整个 socket 集合,只需要传入一个待检测的 socket,减少了内核和用户空间大量的数据拷贝和内存分配。 第二点, epoll 使用事件驱动的机制,内核里维护了一个链表来记录就绪事件,当某个 socket 有事件发生时,通过回调函数内核会将其加入到这个就绪事件列表中,当用户调用 epoll_wait() 函数时,只会返回有事件发生的文件描述符的个数,不需要像 select/poll 那样轮询扫描整个 socket 集合,大大提高了检测的效率。
select/epoll 这个 function会不断的轮询所负责的所有socket,当某个 socket有数据到达了,就通知用户进程。
当用户进程调用了select,那么整个进程会被 block,而同时kernel会“监视”所有select负责的socket,当任何一个 socket 中的数据准备好了,select 就会返回。
这个时候用户进程再调用 read 操作,将数据从 kernel 拷贝到用户进程。
使用 select 以后最大的优势是用户可以在一个线程内同时处理多个socket的 IO请求。
异步 IO(Asynchronous I/O)
Linux 内核从 2.6 开始,也引入了支持异步响应的 IO 操作,如 aio_read, aio_write,这就是异步 IO。
用户进程发起 read 操作之后,立刻就可以开始去做其它的事。而另一方面,从 kernel 的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何 block。然后,kernel 会等待数据准备完成,然后将数据拷贝到用户内存,当 这一切都完成之后,kernel 会给用户进程发送一个 signal,告诉它 read 操作完成了。
知乎陈硕的回答
在处理 IO 的时候,阻塞和非阻塞都是同步 IO。
只有使用了特殊的 API 才是异步 IO。
参考文章
网络基础之五种常见IO模型 https://zhuanlan.zhihu.com/p/364358152 各种IO复用模式之select,poll,epoll,kqueue,iocp分析 https://cloud.tencent.com/developer/article/1373483 select,poll,epoll的区别以及使用方法 https://blog.csdn.net/qq_37869098/article/details/122519170 一文搞懂用户缓冲区与内核缓冲区 https://blog.csdn.net/Jiangtagong/article/details/108703123 JAVA中的BIO/NIO/AIO与Selector https://blog.csdn.net/weixin_44273302/article/details/115269745