Skip to main content

Command Palette

Search for a command to run...

异步系列-序言

Published
2 min read

1. 想法

在工作 2 年的时候,我老大让我去研究seastar这个框架,由于那个时候的技术水平限制我一直不明白它到底做了什么,导致性能上很牛逼。但是在那个时候我开始接触到了异步这个概念,经过了大约 5 年的时间,由于工作经验的沉淀,慢慢的对这个概念有了那么一丝的理解。给自己立了一个 flag,准备在半年之后在工作中分享这个主题

主要会分享内容有

  • asio 的异步框架
  • golang 的协程调度, 本质上是 golang 的异步调度 runtime
  • rust 的 async/await
  • c++ 最新的 stackless coroutine

以上这些内容是目前自己一定会输出的,后面会有一些更加业务层面的异步讨论,不过我现在还没有想好;

2. 关于异步

真的开始这个系列之前,先聊聊异步本身吧, why, what, how;

  • 为什么需要异步呢?

这个观点主要是之前在逛知乎的时候看到了,大概意思是:异步本质上是为了尽可能的提高 cpu 有效利用率; 随着技术的发展 cpu 的速率其实已经远比其他的设备要快很多的,即使内存速度也是比 cpu 要慢几个数量级; 通常程序可以分为 2 种类型,分别为数据密集型 (IO 密集型) 和计算密集型的程序,计算密集型程序主要是通过 cpu 来完成计算任务,比如加密、编码等,对 cpu 有效利用都很高;但是数据密集型 (IO 密集型) 程序,主要是与外界设备进行交互,这种统称为 IO 操作;目前比较多的 IO 设备有:

  • 磁盘/ssd

  • 内存

  • 网络

  • ...

    计算机不同 op 的耗时

这些设备的速度和 cpu 相差好几个数量级,当一个 IO op 从 cpu 发送给设备的时候,这个时候设备的反应对 cpu 来说是非常非常慢的,如果 cpu 等待设备返回的话,那么 cpu 真正有效的工作时间都只有一点点,其他时候都是等待设备的返回。为此硬件工程师和软件工程师都发挥了逆天的能力来改造这些问题,而改造的本质都是操作设备的异步化,不要让 cpu 等待这些设备的反应,而是释放 cpu 去做其他更加重要事情,等设备反应过来再来通知 cpu. 而手段主要有几个:

  • 硬件:通常的解决方式让设备能支持中断的方式来异步通知 cpu; 大部分硬件都是异步化的。当然也有一部分的原因在于一些操作比较简单但是非常消费 cpu,通过加入协作芯片来协助 cpu,比如 DMA 或者 FPGA,DMA 本质上就是觉得用一块专用芯片来进行完成内存 copy; FPGA 的话目前一些大厂会将一些固定的算法或者功能硬件化,比如 gzip,leveldb 中的 compaction 这些操作全部迁移到 fpga 上,这样让 cpu 更加专注于重要的事情。

  • 软件:

    • os: 单进程到多进程到多线程等演变
    • 中断
    • 各种异步框架支持
    • ...

所以异步出现的历史目的是为了提高 CPU 的利用率, 通过异步化操作让 CPU 尽可能都是满负荷的工作,也是 CPU 作为处理器的目标所在。当然异步肯定不只是为了 CPU,只不过在计算机历史的过程中,异步的主要的点在于 CPU 的利用率。 人类社会的分工,流水线产生本身也是异步一种体现,其本质也是为了极大化效率。 下面聊一些计算机异步技术的相关发展:

  1. 从单进程到多进程支持; 如果你明白了所有的异步都是对 CPU 来说的话,那么多进程的的支持其实也是一个异步进化,将一个进程想象为 OS 的一个 OP 操作的话,多进程就是多个 OP,如果一个 OP(进程) 阻塞住 OS 就会进行切换; 针对 CPU 的行为描述应该是:进程 A 你现在有其他的事情要做,那你先去做那个事情吧,等你完成了其他事情的时候再来找我吧;(本质上 CPU 空闲出来可以去做其他的事情了) ,只不过这个 OP 操作太大了,既不能太多切换的代价也很大。
  2. 线程的出现; 本质上也没有变化,只不过线程这个 OP 的粒度更加小,切换成本更加小;
  3. 基于回调的异步处理;按照自己理解,可能大部分的回调实现只不过是基于 os 层面线程模型的情况下的用户层面的优化,当然windows 的 iocp 本质上是操作系统支持的异步化,而 Linux 则是实用多路复用 IO 来模拟的,本质上是同步的。这种优化的本质是:
    • Worker thread 能持续高效的进行工作,将当前可以被运行的任务都运行;这样 worker thread 的 cpu 利用率就很高;
    • 对于会导致 worker thread 被阻塞的操作则都迁移到 IO thread pool,这个线程池可能是 1/n 个线程,这些线程主要做的事情就是用来等待 io 操作的完成并且 worker thread 对应的 op's callback 可以进行了;

回调模型

4. 协程 (coroutine);和基于回调的方式实现逻辑是类似的 (上图),区别点在于对用户的友好性极大的提升。协程的优势在于用同步的逻辑写异步的代码,估计这也是目前 golang 如何大火的原因之一,因为 golang 让写出性能非常不错的程序的门槛拉低了很多很多,只要你用 golang 写代码,基本上性能方面不会差很多,除非你的程序是计算密集型的。

实现逻辑:在用户层构建一个比线程粒度更加小的 op,这个 op 是用户自己来定义的,占用资源更加小、切换成本更加低,并且对底层是无感的;可以极大的增加 op 的个数来并发运行,底层 worker thread 去运行runnable 的 op,这样底层 worker thread 就非常高效。目前有两种实现 coroutine 的方式:

  * stackful : 代表 golang
  * stackless: rust 的`async/await`,C++ 20 最新提出的 coroutine

 对于区别点可以 Google 一下。自己对这块还没有很深入研究,但是本质上在于 stackful 模拟了线程切换上下文切换这么一套东西,而 stackless 则是模拟一套函数调用,而对应的实现就在于 stackful 如果要做到通用,就必须有自己的 runtime,不然不同的架构下面上下文切换的方式会不一样;而 stackless 则是用一套标准的函数调用来实现的,也就是它没有依赖底层操作系统寄存器的东西,用现有的东西来实现的;哈哈,可能讲的不对;

 聊到协程,聊一下一开始线程出现的时候,遇到的问题;当时的网络编程的架构大部分是如下图;叫做每链接每线程的模型,这种模型好处在于简单,而且对 cpu 来说也能提高效率,当年还没类似于 epoll 或者其他的操作系统支持的 api 的时候,用线程将 cpu 的性能提高是唯一的方式,但是这个架构的问题主要在于量到一定级别之后,对 os 来说非常的沉重,这种沉重体现在资源和切换上,所以才会有了[C10K problem](https://en.wikipedia.org/wiki/C10k_problem)的问题;到了协程的时代,其实这个架构就非常流行了,但是区别点在于可能是`one connection one coroutine`,而底层却使用了现代异步模型,从而极大的提高了本身的性能和易用性。

one_connection_one_thread

3. 总结

上面大概的聊了一下关于异步的一些知识;这是我这半年慢慢在思考的东西;我在 twitter 上曾经发言说:难道异步的本质是producer + queue + consumer吗? 虽然这个言论非常的底层或者 low 了点,但是这个模型其实就是人类历史上的流水线模型,所以异步的本质是提高效率; 为什么能提高效率呢?因为 queue 中存在的 task 对于下游 worker 来说是直接可以运行的,在分工明确的情况下,对应下游的 worker 可以一直不停的工作着,这样对于 worker 来说效率就非常高,不需要等待;目前流式计算就是类似于这种模式,而进程内部的话可能 worker 的角色不会划分的如此细。

流水线

对于未来我比较看好 rust 的这种 stackless 的协程模型,其实我最近半年一直思考为什么 rust 如此自然的模型就没人早提出来呢? 目前还没有答案;

这是异步系列的第一篇文档,下一个文章应该是 asio 的分析,会结合原理 +mongo 本身的使用来分析这个库,当然我没有分析它的协程,可能要到后面几篇再聊,比如和 goroutine 一起聊;

More from this blog

Ai时代的工具链

本周是black Friday,我订阅了几个AI服务,还是蛮贵的...不过这样基本上构成我目前整体的知识阅读的过程,随着Ai的不断发展,工具链的替换可能是很重要的一个过程的。我主要订购了以下几个工具: Memo: 这个工具的主要作用是将视频/audio转srt,并且带有ai翻译的工具;当然我觉得它做的非常好的是,它把整个链路做的非常好的,并且可以用本地的资源做audio->text;而且它自带了很多的ai功能,比如对字幕进行进一步的AI的处理,提问,summarize和思维导图等等;目前我主要...

Nov 30, 20251 min read

做了一个噩梦

今天凌晨4点多起来看了一眼丈母娘的发烧是否ok...就导致我有点睡不着的,刷了一会推特之后又开始睡觉了,于是就开始做了一个很可怕的梦。 噩梦 那天,我不知道是在哪里..我带着女儿和我弟出去玩的,貌似是一个风景山区。于是我就带着女儿和弟弟出去玩的;我们走啊走, 沿着一条路一直走..突然看到一个小道有一家饭店的,这个饭店是比较特殊,有很多海鲜的;我看上了一只大龙虾,我问多少钱的,他说大概就70rmb就可以的。。。我觉得很划算的,我心想:我买下来,到时候把老婆叫过来一起吃的,并且告诉她这个才70rmb...

Nov 24, 20251 min read

子女教育-2

下面我分享一个推特上的一个关于子女教育的推 哈哈哈哈,李诞这个视频我看过 我给你分享几个我和我女儿之间的小故事 第一个故事 我经常给小朋友说:你们现在上学的成绩不重要,你们现在数学考试都是语文脑筋急转弯,语文考试都是历史背诵,一点用都没有,你出了社会就知道,社会根本没有选择题,社会要有选择题就好了,最难的是你遇到困难,你连门都找不到。我第一次这样讲的时候是女儿小学4年级,那时候我女儿听的一愣一愣的,她不明白,但是觉得我的理论和学校的不一样,很狂妄,但是她很喜欢,哈哈哈哈。 她什么时候真正明...

Nov 13, 20251 min read

被诈骗-马来西亚

最近我在国内,我老婆在马来;最近在计划搬家的,找的那个房子不包含一些必要的家具,于是我老婆就必须要买点家具的,主要是沙发和餐桌..我们本来计划是说去ikea去买,但是我老婆觉得ikea的家具不便宜,并且款式一般的,最终问了中介找了一个二手平台找找看不错的家具。 我老婆挑了两个家具的,我看了一下价格也不算便宜的,但是我老婆喜欢的,于是我就说你觉得ok那就购买吧。我还顺便问了一下,这个家具能不能线下看一下货的,但是我老婆说这货在很远的地方的,大概是300公里的一个城市的。那我就说这个包邮吗,我老婆说...

Nov 13, 20251 min read

当下和最近想做的事情

1. Current 当下 最近依然还在中国,已经回来快一个月了. 最近一直在忙着带丈母娘看病和住院的。索性一切都还在可控范围内的,丈母娘由于糖尿病控制的很差导致本身的冠心病也复发. 这次去浙江省人民医院去做了造影检查和支架植入的手术的,不过这一切都比我预估的要顺利,我就怕她由于长时间没吃药和高血糖的持续的时间太长了,会带来严重的问题,不过好在没有发生最坏的事情的。 因为做了手术,所以这段时间我和我老婆的姐姐每人轮换的陪床,不过陪床真的好累的,因为睡得很不好的,特别的累。不过好在都结束了,而且丈...

Nov 9, 20251 min read

Keep Move - 永不止步

39 posts

异步系列-序言