ipwx
2022-06-24 10:49:54 +08:00
... 然后书上说的不错,但是没有告诉你的是什么叫“时间太长阻塞”。
实际上你看到的 “每个事件处理都用线程池里的线程去处理” 太泛泛了。具体而言,一般我们都是把 CPU 时间开销大的逻辑丢进线程池然后 await 的。比如算一个 PageRank 分数之类的(笑)。
上面的仁兄提到了 Actor model 。我很感动居然还有人知道这玩意儿,但实际上这玩意儿写普通的业务逻辑不如 async await 高效。举个例子,如果你要读数据库,在多线程 Actor model 下你要怎么做?难不成直接同步阻塞等数据库结果?那不好意思,在大部分语言( C++/Java/Python )中,你又阻塞了一个线程池。纯粹的 Actor model 要求你业务代码把数据库请求 send 给 DBActor ,DBActor 应该是一个负载均衡,后面接着一串多线程的 DBActors 。然后 DBActors 阻塞读写,出来结果再 reply 到业务 Actor 。总之纯粹的 Actor model 写业务代码挺麻烦的。
但是 Actor model 上限很高的,是屠龙刀。它能保证每个 actor 同时只有一个线程在跑,直接保证所有数据的线程安全。这种屠龙刀就不该用来写普通的业务代码。
----
综上所述其实 async / await 写业务代码其实很舒服的,在大部分语言中你不会喜欢其他模式的。
除了 Go 语言。
Go 语言是个工程妥协性非常强的语言,为了解决普通程序员不那么高明这一“人力 BUG”,它做了一些在我看来很丑陋的(但是确实能解决不那么博闻强识的程序员写出来的代码问题)选择。比如它会自动把同步的等待代码直接切出来控制权,强行在 Go vm 层面自动地把同步代码给打断等待。相当于你写了同步等待的网络 /文件 IO ,它自动翻译成 async await 了。这个确实屌,不得不承认,虽然在我看起来很丑陋——
这意味着程序员并不能 100% 控制 Go 语言的实现,你写个比如 PageRank 的算法可能比不上 C++,因为有一堆你不知道它会干嘛的额外动作。
当然,我这么评价 Go 语言,是因为我从线程池、Event loop ( select epoll )、Actor model ( Akka 或者我自己 C++ 手撸的)、callback 之类的东西我都用过。C++、Python 、Scala 、JS 我都写过不少项目。嘛,没那么博闻强识的程序员确实 Go 语言包办更舒服。