什么是IO? 什么是同步/异步IO? 什么是阻塞/非阻塞IO? 什么是IO多路复用? select/epoll跟IO模型有什么关系? 有几种经典的IO模型呢? BIO、NIO、AIO有什么区别呢?
操作系统的一次IO过程
应用程序发起的一次IO操作包含两个阶段:
- IO调用:应用程序进程向操作系统内核发起调用。
- IO执行:操作系统内核完成IO操作。
操作系统内核完成IO操作还包括两个过程:
- 准备数据阶段:内核等待I/O设备准备好数据
- 拷贝数据阶段:将数据从内核缓冲区拷贝到用户进程缓冲区
一个完整的IO过程包括以下几个步骤:
- 应用程序进程向操作系统发起IO调用请求
- 操作系统准备数据,把IO外部设备的数据,加载到内核缓冲区
- 操作系统拷贝数据,即将内核缓冲区的数据,拷贝到用户进程缓冲区
阻塞IO
如果内核数据还没准备好的话,那么应用程序就一直阻塞等待,等待数据从内核拷贝到用户空间,才返回成功。
缺点:如果内核数据没准备好,用户进程将一直阻塞住,浪费性能。
非阻塞IO模型NIO
如果内核数据没有准备好,先返回错误信息给用户进程,让它通过轮训的方式来询问。
缺点:依然存在问题,需要不断的来轮训,同样消耗大量的CPU。可以使用IO复用模型,去解决这个问题。
IO多路复用模型
等到内核数据准备好了,主动通知应用进程再去进行系统调用。 系统提供了一些列的函数(select,poll,epoll),可以同时监控多个fd(文件描述)操作,任何一个返回内核数据就绪,应用进程再发起系统调用。
IO多路复用之select
应用进程通过调用select函数,可以同时监控多个fd,在select函数监控的fd中,只要有任何一个数据状态准备就绪了,select函数就会返回可读状态,这时应用进程再发起recvfrom请求去读取数据。
特点:只需要一次询问即可,大大优化了性能。
缺点:
1 监听的IO的最大连接数有限,linux一般是1024个。
2 select函数返回后,是通过遍历
fdset,找到就绪的描述符fd。
poll解决了连接数限制问题,但是其他问题依然存在,客户端连接增加,效率也会线性下降。 因此,经典的多路复用模型epoll出现。
IO模型之信号驱动模型
信号驱动IO不再用主动询问的方式去确认数据是否就绪,而是向内核发送一个信号(调用sigaction的时候建立一个SIGIO的信号),然后应用用户进程可以去做别的事,不用阻塞。当内核数据准备好后,再通过SIGIO信号通知应用进程,数据准备好后的可读状态。应用用户进程收到信号之后,立即调用recvfrom,去读取数据。
异步IO AIO
BIO,NIO,信号驱动,都有一个缺点,等数据准备好后,从内核空间拷贝到用户空间的时候,用户进程是阻塞的。