Skip to content

ZIO - Async I/O framework for Zig

ZIO is an async I/O framework for Zig that provides:

  • Runtime for executing stackful coroutines (fibers, green threads) on one or more CPU threads
  • Asynchronous I/O layer that makes it look like operations are blocking for easy state management, but using event-driven OS APIs under the hood
  • Synchronization primitives that cooperate with this runtime
  • Integration with standard library interfaces, like std.Io.Reader and std.Io.Writer

It's similar to goroutines in Go, but with the pros and cons of being implemented in a language with manual memory management and without compiler support.

Features

  • Support for Linux (io_uring, epoll), Windows (iocp), macOS (kqueue), most BSDs (kqueue), and many other systems (poll)
  • User-mode coroutine context switching for x86_64, aarch64, arm, thumb, riscv32, riscv64 and loongarch64 architectures
  • Growable stacks for the coroutines implemented by auto-extending virtual memory reservations
  • Multi-threaded coroutine scheduler
  • Fully asynchronous network I/O on all systems
  • Asynchronous file I/O on Linux and Windows, simulated using auxiliary thread pool on other systems
  • Cancelation support for all operations
  • Structured concurrency using task groups
  • Synchronization primitives, including more advanced ones, like channels

Quick Example

Basic TCP echo server:

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

fn handleClient(stream: zio.net.Stream) !void {
    defer stream.close();

    std.log.info("Client connected from {f}", .{stream.socket.address});

    var read_buffer: [1024]u8 = undefined;
    var reader = stream.reader(&read_buffer);

    var write_buffer: [1024]u8 = undefined;
    var writer = stream.writer(&write_buffer);

    while (true) {
        // Read a line from the client
        const line = reader.interface.takeDelimiterInclusive('\n') catch |err| switch (err) {
            error.EndOfStream => break,
            error.ReadFailed => |e| return reader.err orelse e,
            else => |e| return e,
        };
        std.log.info("Received: {s}", .{line});

        // Delay the response a little bit
        try zio.sleep(.fromMilliseconds(1000));

        // Echo the line back
        try writer.interface.writeAll(line);
        try writer.interface.flush();
    }

    std.log.info("Client disconnected", .{});
}

pub fn main() !void {
    const rt = try zio.Runtime.init(std.heap.smp_allocator, .{});
    defer rt.deinit();

    const addr = try zio.net.IpAddress.parseIp4("127.0.0.1", 8080);

    const server = try addr.listen(.{});
    defer server.close();

    std.log.info("TCP echo server listening on {f}", .{server.socket.address});
    std.log.info("Press Ctrl+C to stop the server", .{});

    var group: zio.Group = .init;
    defer group.cancel();

    while (true) {
        const stream = try server.accept();
        errdefer stream.close();

        try group.spawn(handleClient, .{stream});
    }
}

See the Tutorial to get started, or check out the examples in the repository.

Ecosystem

The following libraries use ZIO for networking and concurrency:

  • Dusty - HTTP client and server library
  • nats.zig - NATS client library
  • pg.zig - PostgreSQL client library

Installation

See the Getting Started guide for installation instructions.

License

This project is licensed under the MIT license.