目录
1、同步阻塞IO(BIO)
2、同步非阻塞IO(NIO)
3、多路复用IO
3.1、select(轮询)
3.2、poll(轮询)
3.3、epoll(事件驱动)
3.4、select、poll、epoll总结
4、异步IO模型(AIO)
网络IO涉及的两个对象:用户线程 + 系统内核。
当一个read发生时,会经历两个阶段:
- 数据准备:将数据复制到内核态Buffer中。数据准备阶段,数据可能还未发送完,或者正在发送途中,此时内核态Buffer中的数据并不完整。
- 数据复制:将内核态Buffer中的数据复制到用户态的Buffer中。
阻塞和非阻塞描述的是用户线程调用内核IO操作的方式;
同步和异步描述的是用户线程与内核的交互方式。
- 阻塞:IO操作需要彻底完成后,才返回到用户线程执行用户操作。
- 非阻塞:IO操作被调用后,立即返回一个状态值给用户线程,用户线程就可以去做其他操作。
- 同步:用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行。
- 异步:用户线程发起IO请求后仍继续执行,当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数。
1、同步阻塞IO(BIO)
面向流,同步阻塞IO。服务器一个线程只处理一个客户端的连接。
在IO执行的两个阶段(数据准备和数据复制),用户线程都是阻塞的。
- 数据准备:系统内核还未接收到一个完整的TCP包,需要等待足够的数据到来。此时用户线程进入阻塞状态。
- 数据复制:系统内核等到数据准备好了,会将数据从内核Buffer中拷贝到用户内存中,然后返回结果,用户线程才会解除线程阻塞状态。
优点:在阻塞等待数据期间,用户线程挂起,基本不占用CPU资源。
缺点:高并发场景下,需要大量线程来维护大量网络连接,内存、线程切换开销巨大。
2、同步非阻塞IO(NIO)
用户线程发起read请求:
- 内核数据未准备好:当内核中的数据还未准备好时,内核会立刻返回一个错误给用户线程;
- 线程轮询:如果用户线程接收到内核返回的错误状态,用户线程会不断向内核发起read操作;
- 内核数据已准备好:当系统内核中的数据准备好后, 用户线程阻塞,内核开始复制数据到用户内存,然后返回结果;用户线程读取到数据后,解除阻塞状态。
优点:在内核等待数据的过程中,用户线程不会阻塞。
缺点:内核等待数据过程中,用户线程会不断轮询内核,发送read请求,占用较多的CPU资源。
3、多路复用IO
- 多路:多个TCP连接(即socket或者channel)
- 复用:复用一个或几个线程。
即:同一个线程内同时处理多个TCP连接。 优势是减少系统开销,不必创建/维护过多的线程。
为了避免Nio模型中的轮询等待问题,有了IO多路复用模型,也叫做事件驱动IO(Reactor设计模式),基本原理就是有个函数会不断地轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。
多路复用IO一句话总结:在一个进程里面开辟多个通道,然后进程会去轮询准备就绪的通道,被选中的通道去进行读写操作。
Reactor: 事件分派器,负责事件的注册,删除以及对所有注册到事件分派器的事件进行监控, 当事件发生时会调用Event Handler接口来处理事件。
流程如下:
- 用户线程注册事件处理器,之后可以继续执行做其他的工作(异步)。
- Reactor线程负责调用内核的select/poll/epoll函数检查socket状态。
- 当有socket被激活时,通知相应的用户线程(或执行用户线程的回调函数),执行handle_event进行数据读取、处理的工作。
- 用户线程发起IO请求,读取数据,进行后续业务处理。发起请求时,数据已经到达,所以用户线程不会阻塞。
3.1、select(轮询)
- Select连接文件描述(socket)有限制,默认1024,由FD_SETSIZE设置,采用数组存储。
- 在检查是否有socket需要读写时,轮询,采用线性扫描。
- 每次调用select,都需要把fd_set集合从用户态拷贝到内核态,并在内核遍历传递进来的fd_set,开销大。
3.2、poll(轮询)
Poll模型和selector模型没有本质区别:别在于selector模型有注册数量限制1024,而poll没有限制,因为poll是基于链表存储的。
3.3、epoll(事件驱动)
基于事件驱动的IO方式,没有文件描述符(socket)限制,epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。
- epoll 没有最大并发连接的限制,上限是最大可以打开文件的数目,如:在1GB内存的机器上大约是10万左右。
- 效率提升, epoll 最大的优点就在于它只管你“活跃”的连接 ,而跟连接总数无关,因此在实际的网络环境 中, epoll 的效率就会远远高于 select 和 poll 。
- epoll使用了共享内存,不用做内存拷贝
3.4、select、poll、epoll总结
4、异步IO模型(AIO)
读操作流程如下:
- 用户线程向内核发起异步read请求,向内核注册某个IO操作;
- 请求立即返回,此时用户线程不阻塞,可以去做其他操作;
- 内核完成数据准备和数据复制操作后,内核会给用户线程发送一个信号,或者调用用户线程注册的回调函数,告诉用户线程read操作完成;
- 用户线程读取用户缓冲区的数据,执行线程的后续操作。
优点:真正的异步输入输出,吞吐量高。
缺点:应用程序仅需要进行事件的注册和接收,其余工作都留给了操作系统,需要底层内核支持。
以上内容为个人学习理解,如有问题,欢迎在评论区指出。
部分内容截取自网络,如有侵权,联系作者删除。