Linux 下的五种 IO 模型详细介绍

2019-10-13 20:35:57于海丽

Linux下的五种IO模型

    阻塞IO(blocking IO) 非阻塞IO (nonblocking IO) IO复用(select 和poll) (IO multiplexing) 信号驱动IO (signal driven IO (SIGIO)) 异步IO (asynchronous IO (the POSIX aio_functions))

前四种都是同步,只有最后一种才是异步IO。

阻塞IO模型

在这个模型中,应用程序(application)为了执行这个read操作,会调用相应的一个system call,将系统控制权交给kernel,然后就进行等待(这其实就是被阻塞了)。kernel开始执行这个system call,执行完毕后会向应用程序返回响应,应用程序得到响应后,就不再阻塞,并进行后面的工作。

非阻塞IO

在linux下,应用程序可以通过设置文件描述符的属性O_NONBLOCK,IO操作可以立即返回,但是并不保证IO操作成功。也就是说,当应用程序设置了O_NONBLOCK之后,执行write操作,调用相应的system call,这个system call会从内核中立即返回。但是在这个返回的时间点,数据可能还没有被真正的写入到指定的地方。也就是说,kernel只是很快的返回了这个 system call(只有立马返回,应用程序才不会被这个IO操作blocking),但是这个system call具体要执行的事情(写数据)可能并没有完成。而对于应用程序,虽然这个IO操作很快就返回了,但是它并不知道这个IO操作是否真的成功了,为了知道IO操作是否成功,一般有两种策略:一是需要应用程序主动地循环地去问kernel(这种方法就是同步非阻塞IO);二是采用IO通知机制,比如:IO多路复用(这种方法属于异步阻塞IO)或信号驱动IO(这种方法属于异步非阻塞IO)。

IO多路复用(异步阻塞IO)

和之前一样,应用程序要执行read操作,因此调用一个system call,这个system call被传递给了kernel。但在应用程序这边,它调用system call之后,并不等待kernel的返回结果而是立即返回,虽然立即返回的调用函数是一个异步的方式,但应用程序会被像select()、poll和epoll等具有复用多个文件描述符的函数阻塞住,一直等到这个system call有结果返回了,再通知应用程序。也就是说,“在这种模型中,IO函数是非阻塞的,使用阻塞 select、poll、epoll系统调用来确定一个 或多个IO 描述符何时能操作。”所以,从IO操作的实际效果来看,异步阻塞IO和第一种同步阻塞IO是一样的,应用程序都是一直等到IO操作成功之后(数据已经被写入或者读取),才开始进行下面的工作。不同点在于异步阻塞IO用一个select函数可以为多个描述符提供通知,提高了并发性。举个例子:假如有一万个并发的read请求,但是网络上仍然没有数据,此时这一万个read会同时各自阻塞,现在用select、poll、epoll这样的函数来专门负责阻塞同时监听这一万个请求的状态,一旦有数据到达了就负责通知,这样就将之前一万个的各自为战的等待与阻塞转为一个专门的函数来负责与管理。与此同时,异步阻塞IO和第二种同步非阻塞IO的区别在于:同步非阻塞IO是需要应用程序主动地循环去询问是否有操作数据可操作,而异步阻塞IO是通过像select和poll等这样的IO多路复用函数来同时检测多个事件句柄来告知应用程序是否可以有数据操作。