Skip to content

【Zig 日报】Async I/O in Zig 0.16 #332

@jiacai2050

Description

@jiacai2050

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 的文章,刚刚发布了 0.11 版本,它提供了完整的 std.Io 实现。它使用有栈协程和异步操作系统级 I/O API(Linux 上的 io_uring 或 epoll,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 上联系我,我很乐意提供帮助。

Async I/O in Zig 0.16, today | Lukáš Lalinský

加入我们

Zig 中文社区是一个开放的组织,我们致力于推广 Zig 在中文群体中的使用,有多种方式可以参与进来:

  1. 供稿,分享自己使用 Zig 的心得
  2. 改进 ZigCC 组织下的开源项目
  3. 加入微信群Telegram 群组

Metadata

Metadata

Assignees

No one assigned

    Labels

    日报daily report

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions