写过三年 Wasm 组件,每次接流都要自己造轮子——今天 WASI 0.3 把原生异步彻底放进了 ABI 里
写过三年 Wasm 组件,每次接流都要自己造轮子——今天 WASI 0.3 把原生异步彻底放进了 ABI 里
如果你用 Rust 写过 Wasm 组件,而且用过流式 API,一定会遇到这个别扭的局面:WASI 0.2 里,每个组件都是一个小宇宙,有自己的事件循环。你想用一个组件调用另一个组件的流式接口?对不起,得走网络 socket,哪怕两个组件就运行在同一个进程里。这个限制不是实现上的遗憾——是架构层面的设计问题。2026 年 6 月,WASI 0.3 把这件事彻底修了。
问题的根子:每个组件都是一座孤岛
WASI 0.2 的 I/O 模型是同步的。HTTP 请求会阻塞执行线程,组件内部想用异步流?得自己包装 start/finish/subscribe 那套三部曲。更要命的是:两个都用了流的组件,根本没法组合在一起。
原因是每个组件有自己独立的事件循环。两个组件 A 和 B 都调用了 wasi:http 的流式接口,你想把 A 接在 B 前面,让 A 的输出直接成为 B 的输入?0.2 的世界里这是不可能的——两个事件循环谁也管不了谁。你只能把它们拆成两个网络服务,中间走 HTTP,延迟从纳秒变成毫秒。
这事对服务器端影响不大,反正大家本来就在用 HTTP。但如果你想把 Figma 那种思路搬进服务器——把渲染、压缩、权限校验都拆成独立 Wasm 组件,同进程内用函数调用的速度互相调——0.2 的这个限制就卡住了整个架构。
WASI 0.3:把异步做进了 ABI 里
WASI 0.3.0 在 2026 年 6 月 11 日正式发布,核心变化只有一件事:stream、future、async function 这些异步原语,现在成了 Component Model 规范 ABI 的第一等公民,不再需要外挂。
新的模型是 completion-based 的,思路类似 Linux 的 io_uring 和 Windows 的 IOCP。流式读取不再阻塞线程,而是返回一段数据和一条状态记录——干净关闭还是出错了,调用方自己判断。0.2 时代这个语义根本表达不了,现在原生支持了。
更重要的问题是:谁来管理这些异步操作?答案是主机运行时——Wasmtime、Spin、Fermyon,由它们来统一调度。Rust 组件里用 async trait,Python 组件里用 stackless coroutine,C# 用 async/await,Go 用 goroutine——bindings 生成器可以为每种语言吐出惯用异步写法,但底层都是同一个 ABI 层,天然互操作。一个 Rust 组件可以直接调一个 Python 组件的异步接口,不需要网络,不需要序列化,原生函数调用速度。
服务链:毫秒到纳秒
WASI 0.3 里最直观受益的场景是 HTTP 服务链。wasi:http 接口被拆成了 service 和 middleware 两层,替代了 0.2 时代的 proxy world。写在 Rust 里的权限校验组件,和写在 Python 里的日志组件,现在可以在同一个 Wasmtime 实例里直接串联——延迟从毫秒级降到纳秒级。
Fermyon Spin 早就演示过这个价值:冷启动 1ms 以下,基于 Wasmtime 的 pooling allocator。WASI 0.3 让这个数字继续下探,因为组件之间的调用根本不需要离开运行时。
现在能用什么
Wasmtime 45 已经可以跑 0.3 的候选版本,Wasmtime 46 会默认开启 async 支持。jco 和各语言的 toolchain 也陆续放出 0.3 的工具链。cargo-component 对 Rust 组件的支持已经覆盖了 0.3 的 WIT 定义。
下一步是 0.3.x 的功能迭代:自动取消集成到各语言的惯用法、零拷贝缓冲区优化、线程支持(先协作再抢占)。
对前端意味着什么
这个变化对前端开发者不是直接感知的——但如果你在用 Cloudflare Workers(Rust 是第一等公民)、Shopify Functions(边缘无容器执行)、或任何在 Wasm 上跑后端逻辑的产品,WASI 0.3 让这些架构可以真正用微服务粒度组合,而不用为每个”微服务”付出网络延迟的代价。
组件模型终于可以去掉它最大的架构缺陷了。这条路走了两年,2026 年终于走到了。
下一步:如果你维护一个用了流式 I/O 的 Wasm 组件,现在是时候查一下它的 WASI 目标版本了——升级到 0.3 可能只需要改几行 cargo.toml,但拿到的是原生异步能力和可组合性这两个东西。
评论区
登录后可评论。