从地域到天堂:异步编程模式的革命性演变


从地域到天堂:异步编程模式的革命性演变

仅用于站内搜索,没有排版格式,具体信息请跳转上方微信公众号内链接

作为计算机早期的一名软件工程师,你面临一个棘手的问题。
这一时期操作系统中已经发明了线程,线程非常好用,因此快速流行起来。
但在一些特定场景下线程也有自己的问题,尤其是后端服务器。
大家都会创建一个线程来处理用户请求,如果在此期间发起一个阻塞调用(比如调用下游服务),那么整个线程都会被挂起,在此期间,线程不能执行任何其他工作:
在高并发场景下,这需要创建大量线程,导致巨大的线程创建/切换开销和内存消耗。
这就是最开始的同步编程模型,它简单、直观,但并不高效。
为了解决同步编程模型低效的问题你发明了一个简单而优雅概念:回调函数,callback。
线程不再原地阻塞等待操作完成,而是提供一个函数,告诉系统\“当操作完成时,调用这个函数\“。

至此,你发明了异步编程。
利用异步编程你不必创建大量线程就能高并发处理请求。
但随着项目复杂度增加,你开始遇到新的问题。
当你需要执行一系列依赖的异步操作时,回调函数开始变得难以管理。例如,你需要先获取用户信息,然后获取用户的订单,最后获取订单的详细信息:
这种代码结构被形象地称为\“回调地狱\“(CallbackHell),回调函数本身会切割处理逻辑,而随着嵌套层级的增加,代码变得越来越难以阅读和维护。
使用回调函数实现复杂的控制流(如并行执行多个异步操作,或者有条件地执行异步操作)非常困难,你需要新的异步编程范式。
经过反复思考,你意识到问题的核心在于:回调函数并没有优雅的以线性方式组合异步操作。
该怎么解决这个问题呢?
很简单,再来一层抽象,这种抽象需要创造一种“时间容器”,将“值”与“计算过程”分离,然后以链式调用的方式编排异步操作。
这种抽象就是promise/future。
Promise(或在某些语言中称为Future)。这是一个代表\“未来某个时刻会有结果\“的对象,但是现在你可以基于这个对象进行各种操作,Promise最强大的特性是它支持链式调用,通过. then()方法,你可以指定当未来的结果到来时要执行的操作;通过. catch()方法,你可以处理Promise失败的情况。
这种链式结构成功的实现了以线性方式组合异步操作,它没有回调函数那样的深度嵌套。
除了链式调用,Promise还提供了强大的组合功能,例如Promise. all()可以并行执行多个Promise,当所有Promise都成功时返回所有结果的数组。
这些组合方法让你能够轻松处理复杂的并发场景,这在回调模式中是极其困难的。
Promise彻底改变了你处理异步代码的方式。代码结构变得更加清晰,错误处理更加集中,控制流更加灵活。你终于摆脱了回调地狱的噩梦。
然而,随着你使用Promise的时间增长,你开始注意到一个新的问题:虽然Promise解决了嵌套问题,但它仍然基于回调机制(.then()和. catch()方法本质上是注册回调函数),对于特别复杂的异步逻辑,代码仍然不够直观。
实际上,promise/future说到底只是一种伪同步代码风格而已,开发者仍需在“回调式”思维和“伪同步”代码之间转换。
那么有可能把同步编程的直观和异步编程的高效结合起来吗?
你意识到要想用同步编程来实现异步编程的高效就不能在发起阻塞操作时真的阻塞线程。
怎么做到这一点呢?显然你需要在线程的基础上实现自己的控制流,至此,协程诞生了。。。
我是小风哥,畅销书《计算机底层的秘密》作者,推荐一下我写的专栏《深入理解操作系统》,第二版焕新升级,600+精美手绘图、87节体系课、配套专属讨论群(一群人可以走的更远),如果操作系统对你来说始终是一个黑盒,那么这个专栏就是为你准备的:


文章作者: ZejunCao
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 ZejunCao !
  目录