异步与阻塞的原理及对照
之前写《RabbitMQ的Python客户端pika使用调研》一文时,讨论过关于消息队列异步解耦的功效。此文初次发布时,有些自我认识和表达上的不清晰,还让某大牛朋友的误解,掀起了我们关于异步和阻塞问题概念的讨论。事实是越辩越清,真理是愈辩愈明的。近期我在公司负责的混合云管服务的开发中,涉及到对云主机实例的:创建、开/关机、重启、删除等许多需要调用第三方、且耗时较长,需要用到异步来优化的场景,便觉得有必要就“异步”和“阻塞”这两个概念,做个总结性的梳理。
同步和异步,阻塞和非阻塞, 这几个老生常谈的概念,我们却常常混淆,傻傻分不清楚。一度以为同步肯定就是阻塞,异步必然就是非阻塞,其实他们是描述通信机制的,两个维度下的不同取值,他们两两组合来完整地描述通信机制中,发起调用,和获取返回结果的过程。
同步和异步关注的是如何获取结果
同步:
同步的意思就是调用方需要主动等待结果的返回,即发起调用和获取结果放在一个步骤里完成;
异步:
异步的意思就是不需要主动等待结果的返回,而是通过其他手段比如,状态通知,回调函数等,即发起调用和获取结果,作为两个步骤来完成。
阻塞和非阻塞主要关注的是等待结果返回调用方的状态
阻塞:
是指结果返回之前,调用方当前线程被挂起,不做任何事。即没有结果之前,我作为调用方,啥别的事都不干。
非阻塞:
是指结果在返回之前,线程可以做一些其他事,不会被挂起。即没有结果之前,我作为调用方,我也不干等着,接着做其他的事情。
组合分析
同步和异步,阻塞和非阻塞主要关注的点不同,把通信过程看作一次“问答”过程:
- 同步和异步,关注的是问之后,获取“答案”的方法,可能是“即问即答”(同步),或者“你先问,我过后才答”(异步)。
- 阻塞和非阻塞关注的是“问”之后“问”的一方的状态,可能是“问完先走”,还是“问完干等”。
有人会问同步还能非阻塞,异步还能阻塞?当然是可以的,下面为了更好的说明他们的组合之间的意思,用几个简单的例子说明:
- 1.同步阻塞:同步阻塞基本也是编程中最常见的模型,你去楼下兰州拉面吃拉面,面馆生意火爆,拉面师傅人手不够,拉面需要等待一定的时间。于是你点了一份拉面后,就在店里面一直等,期间不做任何事(包括看手机),等着拉面做好上桌。这个效率当然很低。
-
2.同步非阻塞:同步非阻塞在编程中可以抽象为一个轮询模式,你去楼下兰州拉面,发现吃面要等很久,于是你点了一份拉面后,也不愿意傻傻的等着,你可以去其他地方比如奶茶店,买杯饮品,但是你还是需要时不时地回去拉面馆问,拉面做好没。
-
3.异步阻塞:异步阻塞这个编程里面用的较少,你去楼下兰州拉面,发现吃面要等很久,这个时候你就要了老板电话,然后每隔几分钟时间就给老板打电话,然后你就守着这个电话,一直等问到他的拉面已经做好,期间什么事也不做。这样感觉的确有点傻,所以这个模式用得比较少。
-
4.异步非阻塞:异步非阻塞这也是现在高并发编程的一个核心,也是今天主要讲的一个核心。你去楼下兰州拉面,发现吃面要等很久,你只需要给老板说这是我的电话,拉面做好就打给我。然后你就随心所欲的去玩,也不用操心拉面什么时候做好,拉面一旦做好,电话一响就可以去吃面了。
总结对照
调用方等待结果状态/返回结果方式 | 同步 | 异步 |
---|---|---|
阻塞 | 调用方发起调用后等待返回结果,被调用方结果返回前,调用方不再处理其他问题 | 调用方发起调用后,通过结果获取通道,获取返回结果。未获得结果前,调用方不再处理其他问题 |
非阻塞 | 调用方发起调用后等待返回结果,被调用方结果返回前,调用方继续处理其他问题 | 调用方发起调用后,通过结果获取通道,获取返回结果。未获得结果前,调用方继续处理其他问题 |