同步/异步与阻塞/非阻塞的理解

近期在了解网络编程的时候对同步/异步和阻塞/非阻塞这些概念有一些混淆,所查了一些资料总结了这篇文章。

前言

对于同步/异步与阻塞/非阻塞的理解可能各个领域的人的回答是不一样的,在网络上也有各种各样的说法。这其实是因为不同的人的知识背景不同,并且在讨论这个问题的时候上下文(context)也不相同。本文主要结合网络上的观点以及一些书籍谈谈对同步/异步与阻塞/非阻塞大致概念上的理解,以及在Linux Network IO上的这四个概念的情况。

同步/异步

同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)

所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果。

而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。

打一个不恰当的比方:

你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下”,然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。

阻塞/非阻塞

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

例子:

你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。

在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。

把自己挂起可以是在电话里面一直等着老板回信(同步阻塞),也可以是挂掉电话以后一直等着老板回电过来(异步阻塞)。先玩一会儿可以是电话接通着你去玩一会儿(同步非阻塞),也可以是电话挂了你去玩老板回电给你的时候你回来接(异步非阻塞)。

阻塞和非阻塞描述的是一种状态,同步与非同步描述的是行为方式。

Unix 网络IO

POSIX对同步I/O和异步I/O的定义如下:

  • 同步I/O操作( synchronous I/O opetation) 导致请求进程阻塞,直到I/O操作完成
  • 异步IO操作( asynchronous I/O opetation) 不导致请求进程阻塞。

在Unix中有四种常用的网络IO模型:

  • 阻塞式I/O
  • 非阻塞式I/O
  • I/O复用
  • 异步I/O

其中前者都是同步I/O

阻塞式I/O

默认情况下,所有套接字都是阻塞的。在下面展示recvfrom系统调用中把数据接收过程分成两个阶段:1. 等待数据 2. 数据复制到用户空间。

在等待过程中,进程不能做其他事情,所以是阻塞式的。什么时候调用结束:有结果或者报错的时候,调用才结束,所以是同步的。

非阻塞式I/O

在非阻塞式I/O中进程在进行系统调用recvfrom的时候,如果数据没有准备好线程不会等待,而是不断询问,直到数据准备好,复制数据到用户空间以后,接受数据这个动作才算完成。

因为线程不是一直在等待数据返回,其中也可以做其他的事情,所以是非阻塞式的,对于接受数据这个动作,进程会不断询问,知道最后有结果才算结束,所以是同步式的。

I/O复用

我们阻塞于 select调用,等待数据报套接字变为可读。当se1ect返回套接字可读这一条件时,我们调用 recvfrom把所读数据报复制到应用进程缓冲区。

异步I/O

异步I/O的工作模式时:告知内核启动某个操作,并让内核在整个操作(包括将数据从内核复制到我们自己的缓冲区)完成后通知我们。所以进程不需要一直询问其数据是否准备好

比较

参考: