概述
概念
阻塞和非阻塞是从函数调用角度来说的,而同步与异步是从“读写是谁完成的”角度来说的。
阻塞:如果读写没有就绪或者读写没有完成,则该函数一直等待。
非阻塞:函数立即返回,然后让应用程序轮询。
同步:读写由应用程序完成。
异步:读写由操作系统完成,完成之后,回调或者事件通知应用程序。
按照这个定义可以知道,异步I/O一定是非阻塞I/O,不存在既是异步I/O,又是阻塞I/O,同步可能是阻塞的,也可能是非阻塞的。
I/O多路复用(select,poll,epoll)都是同步I/O,因为read和write函数操作都是应用程序完成的,同时也是阻塞的,因为select,read,write的调用都是阻塞的。
除了上面的四种I/O,还经常听到“事件驱动”一词。这个词在不同的语境中有不同的意思。比如Nginx中所讲的“事件驱动”,其实是Nginx封装的一个逻辑概念,在操作系统层面是基于epoll或者select来实现的。
所以,当将网络I/O模型的时候,一定要注意将的是操作系统层面的I/O模型,还是上次网络框架封装出来的I/O模型(比如asio,比如说Java的NIO,在Linux平台上,底层都是基于epoll的)。
另外,对于“异步I/O”一词,在操作系统的语境和上层应用的语境中,往往指代不一样,在操作系统的语境里,异步 I/O指IOCP或者aio这种真正的异步,epoll不被认为是异步I/O,但在上层应用的语境里,异步I/O往往指的是JavaJDK或者网络框架(Netty)封装出来的概念,底层实现可能是epoll,也可能是真正的异步I/O。
所以在本书后续的章节提到的“异步I/O”,主要指应用层面的语境(底层可能是epoll也可能是真正的异步I/O)。