zig-async - 背景

歴史的経緯

非同期プログラミングの発展

  • コールバック時代(1990年代)
- イベント駆動プログラミング - コールバック地獄の問題

  • Promise/Future(2000年代)
- Java の Future (2004) - JavaScript の Promise (2012)

  • async/await(2010年代)
- C# 5.0 (2012) - Python 3.5 (2015) - JavaScript ES2017

  • 構造化並行性(2020年代)
- Swift Concurrency - Kotlinの構造化並行性

Zigの非同期アプローチ

// Zigは「カラーレス」な非同期を目指す
// 同じコードが同期/非同期両方で動作

fn fetch(url: []const u8) ![]u8 {
    // この関数は呼び出し元のコンテキストに応じて
    // 同期的にも非同期的にも動作可能
}

コンピュータサイエンス的な意味

I/Oモデルの比較

モデル 特徴 使用例
同期ブロッキング シンプル、1リクエスト/スレッド 従来のサーバー
同期ノンブロッキング ポーリング必要 組み込み
非同期ブロッキング select/poll 古いサーバー
非同期ノンブロッキング イベント駆動 現代のサーバー

イベントループのアーキテクチャ

┌─────────────────────────────────────┐
│           イベントループ              │
│  ┌─────────┐  ┌─────────┐          │
│  │タイマー  │  │  I/O    │          │
│  │キュー    │  │キュー    │          │
│  └────┬────┘  └────┬────┘          │
│       │            │               │
│       └─────┬──────┘               │
│             ▼                      │
│     ┌─────────────┐               │
│     │   実行      │               │
│     │ (コールバック)│               │
│     └─────────────┘               │
└─────────────────────────────────────┘

コルーチンとスタック

スタックフルコルーチン:
- 独自のスタックを持つ
- コンテキストスイッチが重い
- 例: goroutine, Lua coroutine

スタックレスコルーチン:
- ステートマシンに変換
- 軽量
- 例: Zig async, Rust async

実践での活用

Webサーバー

// 複数の接続を効率的に処理
pub fn handleConnections(server: *Server) !void {
    while (true) {
        // 非同期で接続を受け入れ
        const conn = try server.accept();

        // 各接続を非同期で処理
        _ = async handleClient(conn);
    }
}

fn handleClient(conn: *Connection) !void {
    defer conn.close();

    const request = try conn.readRequest();
    const response = try processRequest(request);
    try conn.writeResponse(response);
}

データパイプライン

// 非同期ストリーム処理
pub fn processStream(input: *Stream) !void {
    while (try input.next()) |data| {
        // 変換
        const transformed = try transform(data);

        // 並行して出力
        _ = async output.write(transformed);
    }
}

マイクロサービス

┌────────┐     ┌────────┐     ┌────────┐
│Service │────▶│Gateway │────▶│Service │
│   A    │     │(async) │     │   B    │
└────────┘     └────────┘     └────────┘
                   │
                   ▼
              ┌────────┐
              │Service │
              │   C    │
              └────────┘

ゲートウェイは全サービスへの
リクエストを並行して処理

実世界とのギャップ

Zigの非同期の現状

Zig 0.11+ では async/await が一時的に無効化されています:

// 現在のZigでは使用不可
// const result = async someFn();

// 代替: std.Thread を使用
const thread = try std.Thread.spawn(.{}, someFn, .{});
thread.join();

代替アプローチ

// I/O多重化
const std = @import("std");

pub fn main() !void {
    var poller = try std.io.poll.Poller.init(.{});
    defer poller.deinit();

    // ファイルディスクリプタを登録
    poller.add(fd1, .{ .read = true });
    poller.add(fd2, .{ .read = true });

    // イベントを待機
    const events = try poller.poll(timeout);
    for (events) |event| {
        // イベント処理
    }
}

スレッドプールパターン

const ThreadPool = struct {
    workers: []std.Thread,
    queue: Queue(Task),

    pub fn submit(self: *ThreadPool, task: Task) void {
        self.queue.push(task);
    }
};

// ワーカースレッド
fn worker(pool: *ThreadPool) void {
    while (true) {
        const task = pool.queue.pop();
        task.run();
    }
}