这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
Linux/Unix常见IO模型:阻塞(Blocking I/O) 、非阻塞(Non-Blocking I/O) 、IO多路复用(I/O Multiplexing) 、 信号驱动 I/O(Signal Driven I/O) (不常用)和异步(Asynchronous I/O) 。网络IO操作主要涉及到内核和进程,其主要分为两个过程:
- 内核等待数据可操作(可读或可写)——阻塞与非阻塞
- 内核与进程之间数据的拷贝——同步与异步
1 基础概念
① 阻塞(Blocking)和非阻塞(Non-blocking)
阻塞和非阻塞发生在内核等待数据可操作(可读或可写)时,指做事时是否需要等待应答。
- 阻塞: 内核检查数据不可操作,则不立即返回
- 非阻塞: 内核检查数据不可操作,则立即返回
② 同步(Synchronous)和异步(Asynchronous)
同步和异步发生在内核与进程交互时,进程触发IO操作后是否需要等待或轮询查看结果。
- 同步: 触发IO操作 → 等待或轮询查看结果
- 异步: 触发IO操作 → 直接返回去做其它事,IO处理完后内核主动通知进程
2 阻塞I/O
当用户程序执行 read
,线程会被阻塞,一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read
才会返回。阻塞等待的是 内核数据准备好 和 数据从内核态拷贝到用户态 两个过程。过程如下图:
3 非阻塞I/O
非阻塞的 read
请求在数据未准备好的情况下立即返回,可以继续往下执行,此时应用程序不断轮询内核,直到数据准备好,内核将数据拷贝到应用程序缓冲区,read
调用才可以获取到结果。过程如下图:
注意,这里最后一次 read 调用,获取数据的过程,是一个同步的过程,是需要等待的过程。这里的同步指的是内核态的数据拷贝到用户程序的缓存区这个过程。
4 同步I/O
无论 read
和 send
是 阻塞I/O
,还是 非阻塞I/O
都是同步调用。因为在 read
调用时,内核将数据从内核空间拷贝到用户空间的过程都是需要等待的,即这个过程是同步的,如果内核实现的拷贝效率不高,read
调用就会在这个同步过程中等待比较长的时间。
5 异步I/O
真正的异步 I/O 是内核数据准备好
和 数据从内核态拷贝到用户态
这两个过程都不用等待。
当我们发起 aio_read
(异步 I/O) 之后,就立即返回,内核自动将数据从内核空间拷贝到用户空间,这个拷贝过程同样是异步的,内核自动完成的,和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作。过程如下图: