WASI 0.3 发布
摘要
这篇文章宣布了WASI 0.3的发布,该版本通过组件模型将异步原语原生集成到WebAssembly组件中,简化了API并实现了更好的组件组合。
<p><a href="https://lobste.rs/s/kosw9h/wasi_0_3_launched">评论</a></p>
查看缓存全文
缓存时间: 2026/06/12 18:56
# WASI 0.3 正式发布
来源:https://bytecodealliance.org/articles/WASI-0.3
**WASI 0.3 已正式发布,异步现在原生集成于 WebAssembly 组件之中。**
WASI 子组通过投票正式批准了 WASI 0.3.0,将 WASI 重新建立在 WebAssembly 组件模型的异步原语之上。0.3.0 规范现已稳定,运行时和工具链支持也已就绪。
原先 WASI 0.2 中由 `wasi:io` 承担的轮询、输入流、输出流等工作,现已纳入规范的 ABI(https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md),组件模型现在原生提供这些原语。因此,从 WASI 0.2 到 0.3 的大部分变更完全是**机械性的**,并且显著简化了原有的签名。
新的异步原语是组件模型规范 ABI(https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md)的一部分,使绑定生成器能够为目标语言生成地道的异步绑定。
## 组件模型异步 ABI
在 WASI 0.2 中,每个组件都需要自己的事件循环/异步运行时。这意味着各个组件可以在宿主上独立运行,但事件循环之间无法协调。如果一个组件使用了流式或异步 API,就无法与其他任何组件组合。
WASI 0.3 让宿主负责管理所有组件共享的单一事件循环。这是通过将 `stream`、`future` 和 `async` 作为规范 ABI 的一等构造来实现的:
- `stream` 和 `future` 的行为类似于资源类型:每个都是一个拥有的句柄,跨组件边界传递时,所有权从调用方转移给被调用方。与资源类型不同,它们不能被借用。
- 调度由运行时而非每个组件驱动。当值被送达 `future` 时,运行时调度等待该值的任务,即使该值已穿过多个组件边界。写入该值的一方可以是宿主、其他组件,甚至是持有读端的同一组件。
- 异步模型是**基于完成**的,而非**基于就绪**的。这与 Linux 的高效 `io_uring` 以及 Windows 的 IOCP/`IoRing` API 类似。对于需要兼容性的程序,可以在其上模拟 `epoll`/`kqueue` 风格的就绪 API。
- 组件直接导出和导入 `async func`。WASI 0.2 中三步走的 `start-foo`/`finish-foo`/`subscribe` 的繁琐流程已不复存在。
## WASI 接口的变更
0.3 接口中的大部分变更是完全机械性的。WASI 0.2 需要一些技巧才能实现异步,但现在异步已是组件模型的原生特性,我们可以用更符合人体工程学的方式编写相同的内容。以下概述了 WASI 0.2 中通过 `wasi:io` 包编码的模式,以及这些模式在 0.3 中借助组件模型异步的新形态:
| WASI 0.2 (`wasi:io`) | WASI 0.3 (组件模型) |
|----------------------|---------------------|
| `resource pollable` | `future` |
| `resource input-stream` | `stream` |
| `resource output-stream` | `stream` (写入方向) |
| `poll(list)` | 在 `future` 上 `await` (运行时处理) |
| 在资源上 `subscribe()` | 从调用中返回一个 `future<...>` |
| `start-foo`/`finish-foo` | `foo: async func(...)` |
WASI 0.2 的一个问题是,它在每次通过流读取时,都会内联返回终端错误。这意味着调用方只有持续读取才能知道结果。如果读取方提前停止,就无法区分是流关闭还是错误。在 WASI 0.3 中,流现在返回一个额外的 future,该 future 与流消耗了多少无关,从而解决了 WASI 0.2 的流状态问题:
```
// WASI 0.2 read-via-stream: func() -> result<...>
// WASI 0.3 read-via-stream: func() -> tuple<stream<u8>, future<result<stream-status, error>>>
```
## 语言绑定的变更
组件模型的一大超能力是,它让创建与各种语言之间的绑定变得轻而易举。一等异步的加入意味着客户绑定生成器可以利用它来创建对那种语言而言感觉原生的异步绑定。
以 `wasi:http/handler` 接口为例。该接口暴露出一个函数 `handle`,并被标记为 async:
```
interface handler {
handle: async func(request: request) -> result<response, error-code>;
}
```
要用 Rust 实现一个 HTTP 服务器,我们可以使用 wit-bindgen(https://github.com/bytecodealliance/wit-bindgen/tree/main#guest-rust)crate。它将 `interface handler` 映射到 `trait Guest`,并将 `handle: async func` 映射到 `async fn handle`:
```rust
use wasi::http::types::{ErrorCode, Request, Response};
impl Guest for Component {
async fn handle(request: Request) -> Result<Response, ErrorCode> {
// ...
}
}
```
客户绑定生成器的异步支持也正在许多语言中进行,包括
Python(https://github.com/bytecodealliance/componentize-py)、
JavaScript(https://github.com/dicej/componentize-js)、
C#(https://github.com/bytecodealliance/wit-bindgen#guest-c)以及
C(https://github.com/bytecodealliance/wit-bindgen/blob/main/crates/c/README.md)。
所有这些语言都依赖于**无栈协程**。但组件模型的异步 ABI 从设计之初就支持**有栈**和**无栈**协程并存。
Go 就是一个例子。Go 的运行时并不暴露异步和非异步函数,而是能够将看似同步的调用转换为异步调用,并通过称为“goroutine”的虚拟线程提供并发执行。
使用 componentize-go(https://github.com/bytecodealliance/componentize-go/blob/2aa4ad80088ec18cd455cf9b5fecc0c9005fdffe/examples/wasip3/export_wasi_http_handler/handler.go),我们可以通过导出一个 `func Handle` 来实现 HTTP 服务器。这使得流式 body 可以通过进行阻塞调用的 goroutine 来实现。运行时会在 ABI 边界处暂停 goroutine,并在流就绪时恢复它,而不会阻塞程序的其他部分:
```go
package export_wasi_http_handler
import (
. "wit_component/wasi_http_types"
. "go.bytecodealliance.org/pkg/wit/types"
)
func Handle(request *Request) Result[*Response, ErrorCode] {
tx, rx := MakeStreamU8() // ← 1. 创建一对通道
go func() { // ← 2. 生成一个虚拟线程
defer tx.Drop()
tx.WriteAll([]uint8("Hello, world!")) // ← 3. 写入通道
}()
response, send := ResponseNew( // ← 4. 创建一个 HTTP 响应
FieldsFromList([]Tuple2[string, []byte]{
{F0: "content-type", F1: []byte("text/plain")},
}).Ok(),
Some(rx), // ← 5. 将接收端作为 HTTP body 传入
trailersFuture(),
)
send.Drop()
return Ok[*Response, ErrorCode](response) // ← 6. 返回 HTTP 响应
}
```
现在 WASI 0.3 已发布,并支持组件模型异步,客户工具链和宿主运行时将能够开始稳定所有这些功能。在接下来的几周和几个月里,各个项目将陆续宣布对 WASI 0.3 的支持。
## `wasi:http` 的变更
变化最大的接口是 `wasi:http`。我们不仅机械地将基于轮询的接口转换为原生异步接口,还对世界(world)进行了重组,并更改了一些核心抽象。
`wasi:http` 现在暴露了两个世界:`wasi:http/service` 和 `wasi:http/middleware`:
```wit
interface client { /* ... */ }
interface handler { /* ... */ }
// 当由客户绑定生成器使用时,通过 `client` 导入赋予进行 HTTP 调用的能力,
// 并通过 `handler` 导出处理传入的 HTTP 请求。
world service {
import client;
export handler;
}
// 中间件世界是服务世界的超集。
world middleware {
include service; // ← 做 `service` 能做的所有事情。
import handler; // ← 但还要将传入的请求传递给另一个处理器。
}
```
`middleware` 世界取代了 0.2 时代的 `proxy` 世界,用于定义可以转发请求给其他处理器的 HTTP 处理器。WASI 0.3 的新特性是,现在可以实现**服务链**(https://bytecodealliance.org/articles/how-wasm-components-enable-pluggable-middleware):一种组件可以直接相互组合的模式。这意味着作为微服务的组件,如果需要频繁与其他微服务交互,无需通过网络进行。相反,运行时可以选择将它们直接组合在同一个进程内。对于大多数微服务来说,这将调用其他微服务的时间从毫秒降低到纳秒:六个数量级的提升。
## 结论
我们很高兴地宣布,WASI 0.3 已经发布。这意味着:
- **规范已批准**:WASI 0.3 已通过 WASI 子组投票。这是一个稳定版本,这意味着你今天为其编译的程序将在未来保持可用。即使我们继续每两个月发布一个补丁版本(例如 0.3.x)。
- **Wasmtime**:Wasmtime 45 今天已运行最新的候选版本,Wasmtime 46 将默认启用组件模型异步并附带 WASI 0.3.0。
- **Jco 紧随其后**:JavaScript 组件模型工具链 jco 也支持所有 WASI 0.3。默认启用支持的版本即将发布。
- **客户工具链即将到来**:与此同时,在客户工具链中启用 WASI 0.3 的工作正在进行中。随着这些发布,你将能够在 Rust、Go、JavaScript、Python 等语言中编写 WASI 0.3 组件。
开始使用 WebAssembly 组件的最佳途径是 Wasm 组件模型书籍(https://component-model.bytecodealliance.org/)。
如需查看变更的完整列表,请参阅 WASI 0.3.0 发布说明(https://github.com/WebAssembly/WASI/releases/tag/v0.3.0)。
如果你想知道 WebAssembly 组件和 WASI 的下一步计划,请参阅《通往组件模型 1.0 之路》(https://bytecodealliance.org/articles/the-road-to-component-model-1.0)。
WASI 0.3 是社区共同努力的成果。感谢 WASI 子组中设计、讨论和完善此版本的每一位成员,感谢构建实现使其成真的运行时和工具链维护者,以及每一位提交 issue、审查 PR 或提出困难问题使规范更完善的贡献者。感谢所有基于 WASI 构建的用户;你们的组件、反馈以及尝试候选版本的意愿塑造了最终发布的内容。
组件模型的原生异步历经数年打磨,它开启了一个新的篇章:异步和可组合性成为一等公民,相同的原语服务于每一种语言。我们迫不及待地想看到你在此基础上构建的内容。
欢迎来到 WASI 0.3。
相似文章
WASI 0.3.0 发布
WASI 0.3.0(预览版3)已发布,通过组件模型的 future 和 stream 类型,用原生异步功能替代了之前显式的流和轮询接口。
weblings:在 WASM 内部将 Rust 编译为 WASM
Weblings 是一个编译为 WebAssembly 的 Rust 编译器工具链,通过带有 playground 和 Rustlings 练习的网页 UI,支持在浏览器中直接编译和执行 Rust 代码。
micropython-wasm 0.1a0
micropython-wasm 0.1a0 发布,使MicroPython能够在WebAssembly环境中运行,实现沙盒化和可移植性。
luau-wasm 0.1a0
luau-wasm 0.1a0,一个 Luau 脚本语言的 WebAssembly 构建版本,已发布。
SpaceWASM:NASA/JPL 用于航天器序列化的 WebAssembly 解释器
SpaceWASM 是一个来自 NASA/JPL 的开源 WebAssembly 解释器,专为航天器机载序列化设计,注重确定性内存使用和在资源受限环境下的流式处理能力。