要问技术多NB,请问IO模型知多少? | 下篇

图片

 1   IO 模型之IO多路复用

解决NIO的思路就是降解无效的系统调用,如何降解呢?我们一起来看看以下几种IO多路复用的解决思路。

1.1. IO多路复用之select/poll

Select是内核提供的系统调用,它支持一次查询多个系统调用的可用状态,当任意一个结果状态可用时就会返回,用户进程再发起一次系统调用进行数据读取。换句话说,就是NIO中N次的系统调用,借助Select,只需要发起一次系统调用就够了。其IO流程如下所示:

图片


但是,select有一个限制,就是存在连接数限制,针对于此,又提出了poll。其与select相比,主要是解决了连接限制。

select/epoll 虽然解决了NIO重复无效系统调用用的问题,但同时又引入了新的问题。问题是:

  • 用户空间和内核空间之间,大量的数据拷贝

    扫描二维码关注公众号,回复: 12483163 查看本文章
  • 内核循环遍历IO状态,浪费CPU时间

换句话说,select/poll虽然减少了用户进程的发起的系统调用,但内核的工作量只增不减。在高并发的情况下,内核的性能问题依旧。所以select/poll的问题本质是:内核存在无效的循环遍历。

1.2. IO多路复用之epoll

针对select/pool引入的问题,我们把解决问题的思路转回到内核上,如何减少内核重复无效的循环遍历呢?变主动为被动,基于事件驱动来实现。其流程图如下所示:


epoll相较于select/poll,多了两次系统调用,其中epoll_create建立与内核的连接,epoll_ctl注册事件,epoll_wait阻塞用户进程,等待IO事件。


epoll,已经大大优化了IO的执行效率,但在IO执行的第一阶段:数据准备阶段都还是被阻塞的。所以这是一个可以继续优化的点。

 2   IO 模型之信号驱动IO(SIGIO)

信号驱动IO与BIO和NIO最大的区别就在于,在IO执行的数据准备阶段,不会阻塞用户进程。如下图所示:当用户进程需要等待数据的时候,会向内核发送一个信号,告诉内核我要什么数据,然后用户进程就继续做别的事情去了,而当内核中的数据准备好之后,内核立马发给用户进程一个信号,说”数据准备好了,快来查收“,用户进程收到信号之后,立马调用recvfrom,去查收数据。

乍一看,信号驱动式I/O模型有种异步操作的感觉,但是在IO执行的第二阶段,也就是将数据从内核空间复制到用户空间这个阶段,用户进程还是被阻塞的。

综上,你会发现,不管是BIO还是NIO还是SIGIO,它们最终都会被阻塞在IO执行的第二阶段。那如果能将IO执行的第二阶段变成非阻塞,那就完美了。

 3   IO 模型之异步IO(AIO)

异步IO真正实现了IO全流程的非阻塞。用户进程发出系统调用后立即返回,内核等待数据准备完成,然后将数据拷贝到用户进程缓冲区,然后发送信号告诉用户进程IO操作执行完毕(与SIGIO相比,一个是发送信号告诉用户进程数据准备完毕,一个是IO执行完毕)。其流程如下:

图片

所以,之所以称为异步IO,取决于IO执行的第二阶段是否阻塞。因此前面讲的BIO,NIO和SIGIO均为同步IO。

图片


猜你喜欢

转载自blog.51cto.com/15057823/2632455