0x00 引言
Linux系统中的IO模型主要分为五种[1]:1.阻塞IO;2.非阻塞IO;3.IO多路复用;4.信号驱动IO;5.异步IO
前四种都可以归类为同步IO,目前最常用的是IO多路复用,本文将详细介绍这五种IO模型,参考文献[2]。
0x01 同步IO模型 - 阻塞IO
1 | 1 单线程 |
1、单线程
在没有使用IO多路复用机制时,有BIO、NIO两种实现方式,但是会出现阻塞或者开销大的问题。其中前者即为阻塞IO,服务端会阻塞在accept函数,在客户端connect建立连接后,又会阻塞在read函数,直到客户端执行write函数。
2、多线程
为了解决单线程无法处理多个IO的问题,可以使用多线程的方式:
0x02 同步IO模型 - 非阻塞IO
虽然多线程阻塞IO能够使每个线程各自处理自己的dowork(),但是这还称不上非阻塞IO,因为每个线程中的read函数仍然会阻塞当前线程。非阻塞IO(NIO)需要通过设置,将read函数稍作改变,执行read时会判断fd文件描述符(下文简称fd)是否就绪,若没有则返回-1直接退出,而不是阻塞在原地一直等待fd就绪。
0x03 同步IO模型 - IO多路复用
非阻塞IO还存在许多可优化的地方,比如不需要为每个fd开一个线程去监听。解决方案是分化一个管理线程用于循环read每个fd。
现在线程就分成了三类:1.主线程(监听连接);2.管理线程(遍历fd);工作线程(处理业务)
虽然从每一个子线程read自己的fd变成了只有一个管理线程read所有的fd,但fd一旦多起来,管理线程在用户态read未就绪的fd时也存在着一定的性能消耗。select/poll/epoll即是为解决这个问题而产生的:
1 | 1 select/poll |
select | poll | epoll | |
---|---|---|---|
数据结构 | bitmap | 数组 | 红黑树 |
最大连接数 | 1024 | 无上限 | 无上限 |
fd拷贝 | 每次调用selec拷贝 | 每次调用poll拷贝 | fd首次调用epoll_ctl拷贝,每次调用epoll_wait不拷贝 |
工作效率 | 轮询O:(n) | 轮询:O(n) | 回调:O(1) |
1、select/poll
select是操作系统提供的系统调用函数,通过它我们可以把一个文件描述符的数组发给操作系统,让操作系统去遍历,确定哪个文件描述符可以读写,然后告诉我们去处理。
poll跟select几乎一模一样,只是取消了select的最大fd个数1024的限制
1 |
|
2、epoll
epoll也就是现在市面上使用最多的方式,解决了刚刚select所说的三个缺点:内核存在拷贝,内核是同步IO,只返回个数
0x04 同步IO模型 - 信号驱动IO
0x05 异步IO模型
0x06 引用文献
[1]https://cloud.tencent.com/developer/article/1005481
[2]https://blog.csdn.net/weixin_44806108/article/details/124748656