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.Readerandstd.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,riscv64andloongarch64architectures - 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.