

IO模型:同步、异步、阻塞、非阻塞
source link: https://songlee24.github.io/2016/07/19/explanation-of-5-IO-models/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

IO模型:同步、异步、阻塞、非阻塞
前言:
在Linux的网络编程中,同步IO(synchronous IO)、异步IO(asynchronous IO)、阻塞IO(blocking IO)、非阻塞IO(non-blocking IO)究竟是什么?它们之间又有什么联系和区别? 本文是我对这个问题的答案整理的笔记,参考《UNIX网络编程.卷1》
一、IO模型
在《UNIX网络编程.卷1》第6.2节介绍了五种IO模型,分别是:
- 阻塞式IO(blocking IO)
- 非阻塞式IO(non-blocking IO)
- IO复用(IO multiplexing)
- 信号驱动式IO(signal driven IO)
- 异步IO(asynchronous IO)
通常一个 socket 上的读操作包含两个阶段:
- 等待数据准备好;
- 将数据从内核拷贝到进程中。
上述几种IO模型就是在这两个阶段上各有不同的情况。
1.1 阻塞式IO
默认情况下,Linux下的所有socket都是阻塞的。以 UDP 的recvfrom
调用为例:
当进程调用recvfrom
时,该函数直到①数据报到达且被复制到应用进程缓冲区;②或者发生错误(比如被信号中断)才返回。
所以,阻塞式IO的特点就是在I/O执行的两个阶段都被阻塞了——阻塞等待数据,阻塞拷贝数据。
1.2 非阻塞式IO
Linux下可以通过fcntl
将 socket 设置为非阻塞模式。
当对一个非阻塞 socket 执行读操作时,如果内核中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个EWOULDBLOCK
错误;如果内核中有数据准备好了,它会立即将数据拷贝到用户内存,并成功返回。
由于非阻塞I/O在没有数据时会立即返回,故用户进程通常需要循环调用recvfrom
,不断地主动询问内核数据是否ready。
所以,非阻塞式IO的特点是在I/O执行的第一个阶段不会阻塞线程,但在第二阶段会阻塞。
1.3 IO复用
IO复用(IO multiplexing),也称事件驱动IO(event-driven IO),就是在单个线程里同时监控多个套接字,通过 select 或 poll 轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。
可以看出,进程阻塞在select
调用上,等待有套接字变为可读;当有套接字可读以后,调用recvfrom
把数据报从内核复制到用户进程缓冲区,此时进程阻塞在IO执行的第二个阶段。
如上图整个用户进程其实是一直被阻塞的,但IO复用的优势在于可以等待多个描述符就绪。
所以,IO复用的特点是进行了两次系统调用,进程先是阻塞在 select/poll 上,再是阻塞在读操作的第二个阶段上。
1.4 信号驱动式IO
信号驱动式IO(signal-driven IO),就是让内核在描述符就绪时发送SIGIO
信号通知用户进程。
首先需要开启 socket 的信号驱动式IO功能,然后通过sigaction
系统调用注册SIGIO信号处理函数 —— 该系统调用会立即返回。当数据准备好时,内核会为该进程产生一个SIGIO信号,这时就可以在信号处理函数中调用 recvfrom 读取数据了。
所以,信号驱动式IO的特点就是在等待数据ready期间进程不被阻塞,当收到信号通知时再阻塞并拷贝数据。
1.5 异步IO
异步IO(asynchronous IO)其实用得很少,在Linux 2.5 版本的内核中首次出现,在 2.6 版本的内核中才成为标准特性。
用户进程在发起aio_read
操作后,该系统调用立即返回 —— 然后内核会自己等待数据ready,并自动将数据拷贝到用户内存。整个过程完成以后,内核会给用户进程发送一个信号,通知IO操作已完成。
异步IO与信号驱动式IO的主要区别是:信号驱动式IO是由内核通知我们何时启动一个IO操作,而异步IO是由内核通知我们IO操作何时完成。
所以,异步IO的特点是IO执行的两个阶段都由内核去完成,用户进程无需干预,也不会被阻塞。
1.6 五种IO模型的比较
可以看出,前4种模型的主要区别在于第一阶段,因为它们的第二阶段是一样的:都是阻塞于recvfrom
调用,将数据从内核拷贝到用户进程缓冲区。
二、阻塞vs非阻塞,同步vs异步
回到本文开头的那个问题:同步IO、异步IO、阻塞IO、非阻塞IO究竟是什么?它们之间又有什么联系和区别?
阻塞IO vs 非阻塞IO
上面介绍阻塞式IO模型、非阻塞式IO模型时已经说明了两者的区别:
- 阻塞I/O会一直阻塞用户进程直到操作完成
- 非阻塞I/O在内核的数据还没准备好的情况下会立即返回
同步IO vs 异步IO
POSIX是这样定义的:
- A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes. —— 同步IO操作导致进程阻塞,直到IO操作完成。
- An asynchronous I/O operation does not cause the requesting process to be blocked. —— 异步IO操作不导致进程阻塞。
上面定义中的I/O operation
是指真正的I/O系统调用,比如recvfrom
,所以阻塞式I/O模型、非阻塞式I/O模型、I/O复用模型、信号驱动式I/O模型都属于同步I/O。—— 只有异步I/O模型属于POSIX定义的异步I/O,因为在异步I/O模型中,用户进程是将整个I/O操作都交给内核来完成,内核完成后发信号通知,在此期间用户进程完全不用去理会。
Recommend
-
68
网上有很多讲同步/异步/阻塞/非阻塞/BIO/NIO/AIO的文章,但是都没有达到我的心里预期,于是自己写一篇出来。 常规的误区 ...
-
42
网上有很多讲同步/异步/阻塞/非阻塞/BIO/NIO/AIO的文章,但是都没有达到我的心里预期,于是自己写一篇出来。 常规的误区 假设有一个展示用户详情的需求,分两步,先调用一个HTTP接口拿到详情数据,然后使用适合的视图展示详情数据。 如果网速很慢,代码发
-
24
来自: 掘金(作者:未读代码) 原文链接: https://juejin.im/post/5dc37d895188256d85228de6 几个概念 阻塞IO和 非阻塞IO 这两...
-
8
看了你就懂的同步与异步、阻塞与非阻塞 2020-04-26...
-
1
异步同步阻塞非阻塞详解 2017-07-31 相信刚入门计算机科学的小伙伴们来说,这四个词–异步,同步,阻塞,非阻塞,直接搞晕,因为单单理解四个词就算了,他们还能组合,同步阻塞,同步非...
-
4
同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock) 两者定义的针对目标不同,异步同步是针对 响应 本身的,阻塞非阻塞是针对 请求 本身的。 本质上没有关系 同步与异步是关于指令执行顺序的。 阻塞...
-
6
linux IO —— 理解阻塞/非阻塞、同步/异步 作者: 邹成卓 2022-05-30 13:50:16 分类:
-
8
阻塞非阻塞和同步异步的区分 参考一些书籍 编程中一直对...
-
5
上两篇文章讲过了BIO与非阻塞I...
-
7
V2EX › 程序员 今天一早的搜索,终于对同步、异步、阻塞、非阻塞、中断、轮询、多线程,协程这几个概念有了理解 ...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK