Zig / 教程资料

现在就使用 Zig 0.16 中的异步 I/O

约 6 小时前发布

原文链接https://lalinsky.com/2026/05/11/async-io-in-zig-016-today.html

Zig 0.16 上个月发布了,它带来了 std.Io,一个用于 I/O 和并发的跨平台接口。这对生态系统来说是重要的一步。库现在可以针对一个标准的 I/O 抽象来编写,独立于运行时,而应用程序开发者可以插入他们想要的任何实现。

0.16 版本中唯一可用的实现是 std.Io.Threaded,它使用了一个线程池。当你生成并发任务时,它会创建操作系统线程来运行它们。让我们通过一个简单的例子来看看它是如何工作的:

const std = @import("std");

const num_tasks = 10_000;

fn task(io: std.Io) std.Io.Cancelable!void {
    try io.sleep(.fromSeconds(10), .awake);
}

pub fn main(init: std.process.Init) !void {
    var group: std.Io.Group = .init;
    for (0..num_tasks) |_| {
        try group.concurrent(init.io, task, .{init.io});
    }
    try group.await(init.io);
}

这会生成 10,000 个并发任务,每个任务睡眠 10 秒钟。在我的机器上,它大约在 20 秒内完成:

$ time ./std_demo

real    0m20.158s
user    0m2.258s
sys     0m10.098s

开销来源于生成操作系统线程。如果你尝试将这个数字增加到 50,000 个任务,由于线程限制(Linux 上的 ulimit -u),它很可能会在大多数系统上失败。

这不仅仅是一个随意的基准测试。异步 I/O 的存在是为了解决一个实际问题:拥有大量连接客户端的网络服务器。你不会想为每个客户端连接都生成一个操作系统线程。这就是为什么我们需要事件循环、协程和异步 I/O。

标准库中有一个 std.Io.Evented,它的目标是在 Linux 上使用 io_uring,在 BSD/macOS 上使用 kqueue。不过它仍然是一项正在进行中的工作,缺少许多函数,并且目前无法编译。

我之前写过关于 zio 的文章,并且我刚发布了一个完整 std.Io 实现的 0.11 版本。它使用了栈式协程和异步操作系统级 I/O API(Linux 上的 io_uringepoll,BSD/macOS 上的 kqueue,Windows 上的 IOCP)。下面是用 zio 实现的相同示例:

const std = @import("std");
const zio = @import("zio");

const num_tasks = 10_000;

fn task(io: std.Io) std.Io.Cancelable!void {
    try io.sleep(.fromSeconds(10), .awake);
}

pub fn main(init: std.process.Init) !void {
    const rt = try zio.Runtime.init(init.gpa, .{});
    defer rt.deinit();

    const io = rt.io();

    var group: std.Io.Group = .init;
    for (0..num_tasks) |_| {
        try group.concurrent(io, task, .{io});
    }
    try group.await(io);
}

代码几乎完全相同。你只需初始化一个 zio 运行时,并使用它的 io() 方法来获取 std.Io 接口。使用 zio,同样的 10,000 个任务大约在 10 秒内完成:

$ time ./zio_demo

real    0m10.606s
user    0m3.136s
sys     0m7.126s

这是预期的时间,因为所有任务都在真正并发地运行。你可以将这个数字增加到 50,000 个或更多任务,它将继续工作,仅受可用内存的限制。

你可以将 io 实例用于任何你使用 std.Io.Threaded 的场景。例如,要使用 std.http.Server 编写一个 HTTP 服务器,只需传入 zio 的 io,它将以同样的方式工作。

如果你想在 Zig 0.16 中使用标准 API 进行异步 I/O,你不需要等待 std.Io.Evented 就绪。Zio 的实现仍然是新的,所以如果你遇到任何问题,请在 GitHub 上联系我,我很乐意帮忙。

加入开源交流群

请加站长微信,免费进入交流群,和开源爱好者一起讨论。

站长微信二维码