Tokio与Rayon陷阱:为什么Async/Await无法实现并发
时间:2026-08-05 | 作者:宇宙开黑者 | 阅读:0过去几年,智能合约里那种“异步调用”写法(比如 Solidity 里的 await)逐渐成了主流。因为它看起来太简单了——开发者能写出跟同步代码几乎一模一样的逻辑,感觉就像在写普通程序。
但别被这种“熟悉”骗了。表面上的顺手,背后藏着极其复杂的结构问题。它把控制流藏起来了,让硬件真正的运行方式变得模糊,最后把调度压力全甩回开发者手里。
Vitalik Buterin 在早期讨论智能合约设计时说过类似的话:“简单”是指你看着眼熟、上手快的东西,而“简洁”是指内部结构不乱、没那么多绕弯子的地方。异步调用写起来确实“简单”,但运行起来太“复杂”了。
以太坊核心开发者曾在一场技术分享里提到这种架构上的转变:
相比轻量级线程、通道和 select 机制,异步/等待对语言和虚拟机实现者来说更省事、更轻量……但它把一部分复杂性推回给了写代码的人,常常导致“有色函数”问题——也就是你调用一个异步函数,周围所有东西都得变成异步。不过重点在于:不管你提供哪种并发模型,最好只给一种。因为同时提供多种并发实现的环境,很容易出乱子。
这些关于“多种并发实现”和异步/等待的评论,恰恰就是今天很多区块链项目在生产环境里踩坑的地方。
生产陷阱:把“异步”和“并发”搞混了
异步/等待最根本的陷阱,是它把“异步”(等待 I/O 时让出控制权)和“并发”(同时处理多个任务)混为一谈。
这个语法本身就是个陷阱。它在底层把交错的状态机伪装成了一个个独立的顺序线程。开发者被这种错觉迷惑,写一个异步函数就跟写阻塞代码一样——先调个合约接口拿数据,然后立刻处理。
但问题来了:如果数据处理涉及解析一个 10MB 的 JSON 响应、遍历一个巨大的集合,或者做一笔计算量很大的零知识证明,会发生什么?
协作式调度直接卡住了。
在像 EVM 或者 Node.js 这类协作式运行时里,线程在遇到 await 之前是不会主动让出 CPU 的。一个函数里哪怕只跑 50 毫秒的密集计算,整个线程就停住了。一瞬间,成千上万个无关的请求延迟飙升,系统变得像死了一样。与此同时,硬件资源根本没被用上。
破碎的承诺:开发者成了调度员
当这些延迟尖峰出现时,解决方案永远一模一样:把运行时拆开。用 EVM 处理链上交互,把计算密集型任务丢到专用线程池里。
最近一些项目的事后复盘,把这种痛苦暴露得很清楚。PostHog 和 Meilisearch 的工程团队都写过文章,记录在生产里解决这些复杂性的真实经历。开发者必须仔细分析每个函数,判断它属于“链上交互池”还是“计算池”,然后手动编排它们之间的消息传递。
如果开发者得手动给 I/O 和计算分区,严防死守边界避免死锁,还得用两种不同的思维模型在两个运行时之间传数据,那异步抽象就已经失败了。这个语言特性本来承诺要隐藏并发的复杂性,结果却把应用开发者变成了底层调度员。
默认无上限,默认就是 OOM
异步/等待运行时的第二种失败模式,是它们能让你毫无阻碍地无限扩容。
调用一个 spawn 操作很便宜。当下游的预言机或跨链桥在流量高峰时变慢,入口循环还在愉快地接受新连接、生成新任务。
因为异步任务和内存分配在这些生态里默认通常不设限制,系统不会主动拒绝请求。积压的任务在队列里无限堆着。应用的内存消耗一路飙升,直到操作系统内存不足(OOM)杀手直接干掉进程。
主流平台的事后分析反复指向同一个根因:队列不能解决过载问题,它只是把崩溃推迟了,而且让崩溃变得更灾难。无限容量是个谎言,默认假装无限容量是危险的。
工作窃取的神话
当系统遇到这些瓶颈,开发者往往指望更智能、能抢占、能工作窃取的调度器来均衡负载。假设是:如果一个核心空闲,它应该从繁忙的核心那里偷任务来保证公平。但在大规模场景下,公平性是吞吐量的敌人。工作窃取会破坏 CPU 缓存局部性。
当某个项目把 Erlang BEAM 虚拟机推到 100 多个核心的机器上时,系统开始卡顿。正如 Robin Morisset 详细描述的那样,试图偷取工作的空闲线程把所有 CPU 周期都花在了争抢全局 runq_lock 上——一个用于同步调度器运行队列的锁。
就算用了优化锁,把状态机搬到不同的 CPU 核心,也意味着放弃 L1 和 L2 缓存。如果每个被偷的任务都要付出 100 纳秒以上的主内存读取代价,那公平性根本不重要。如果你已经因为生产需要,被迫手动对链上交互任务和计算任务进行线程分区,那么通用的工作窃取算法早就让你失望了。你比运行时更清楚工作负载的拓扑结构。
另一种选择
我已经厌倦了异步/等待的复杂性和各种陷阱。我想要 BEAM 那种坚如磐石的容错能力,但不想忍受垃圾回收和全局工作窃取这些不透明的东西。正如 Leslie Lamport 很久以前就主张的,状态机才是并发编程的数学基础。异步/等待只是编译器的魔法,试图用很蹩脚的方式把状态机藏起来。
与其藏起状态机,为什么不把它公开,让用户拥有更好的控制原语?结果就是 Project Tina:一个固执己见、无共享、每核线程的并发框架。
Tina 用严格的约束来保证巨大的吞吐量和可靠性:
- 一种原语,一种心智模型。 没有 async 或 await,没有 Promise,也没有 Future。你写一个 Isolate——一个并发工作单元。处理程序就是一个标准的同步函数,对消息做出反应,然后返回 Effect。
- 每个核心一个线程,不共享任何东西。 Tina 把工作负载按操作系统线程分片。没有工作窃取。Isolate 从不迁移。所有跨核心通信都通过消息子系统进行。
- 严格限制。 内存在进程启动时预先分配。邮箱有严格上限。如果流量高峰来了,邮箱满了,调用者会立刻收到通知。系统可预测地卸掉负载,而不是让 OOM 把进程搞崩。
- 架构确定性。 在现代异步运行时里,任务轮询顺序和线程池调度是不透明、不确定的混乱来源。你很少确切知道你的任务会在何时何地醒来。Tina 去掉了这个。调度器是每个核心上一个严格、可见、单线程的循环。因为框架明确控制执行顺序、I/O 和时钟,系统的行为完全可预测。这解锁了 Tina 的终极超能力:确定性模拟测试(DST)。你可以在单线程上模拟网络分区或丢消息,相同的种子每次都会产生完全一样的执行顺序。
异步/等待让并发写起来容易,但让系统跑起来复杂。通过强制开发者提前显式管理状态转换、严格的内存限制和深思熟虑的架构拓扑,我用结构保证取代了运行时魔法。因为:
可预测性胜过简洁。
脚注
- Vitalik Buterin,“简单变得容易”,Devcon 演讲。
- 以太坊核心开发者,“我们做对了什么,我们做错了什么”,某技术会议。
- PostHog Engineering,“解开共识与计算”,posthog.com/blog。
- Louis Dureuill,“不要混合链上和链下逻辑”,blog.dureuill.net。
- Robin Morisset,“针对多核架构优化 BEAM 调度器”,Code BEAM Europe。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- 五步销毁7000万枚WBS,币价迎来新行情?
- 时间:2026-08-05
-
- 什么是Synthetix(SNX)数字货币?运作方式、代币规则与购买方法全解
- 时间:2026-08-05
-
- 以太坊Fusaka升级完成,L2数据可用性再提升
- 时间:2026-08-05
-
- 瑞波币涨了?跟黄金有关吗?(60字符内)
- 时间:2026-08-05
-
- 例如a16z说的隐私赛道是啥?到底该怎么做,为什么2026年值得关注?
- 时间:2026-08-05
-
- 以太坊数据块上限上调至21是什么意思?一文搞懂
- 时间:2026-08-05
-
- 加密货币股为什么暴涨?原因及投资建议
- 时间:2026-08-05
-
- 一文读懂:ETH质押巨变,验证者退出队列将清空!
- 时间:2026-08-05
精选合集
更多大家都在玩
大家都在看
更多-
- 温暖的味道第41集剧情介绍
- 时间:2026-10-08
-
- 温暖的味道第40集剧情介绍
- 时间:2026-10-08
-
- 温暖的味道第39集剧情介绍
- 时间:2026-10-08
-
- 温暖的味道第38集剧情介绍
- 时间:2026-10-08
-
- 温暖的味道第37集剧情介绍
- 时间:2026-10-08
-
- 温暖的味道第36集剧情介绍
- 时间:2026-10-08
-
- 温暖的味道第35集剧情介绍
- 时间:2026-10-08
-
- 温暖的味道第34集剧情介绍
- 时间:2026-10-08
