Zen言語のasync標準ライブラリ紹介〜event.Batch①〜

はじめに

けっこう標準ライブラリが充実しているわけですが、ドキュメントがないのがもったいないですね。 まとまった時間が取れないので、ちょこちょこ書いていくシリーズです。

リクエストあれば、優先する、かも?

async関連のライブラリはstd.event下にあります。

今回は複数のasync関数を実行するevent.Batchです。

async自体の説明は、またそのうちに。

std.event.Batch

まず、2つのasync関数を実行するBatchです。

const std = @import("std");
const event = std.event;
const testing = std.testing;

test "std.event.Batch" {
    var batch = event.Batch(usize, 2, .auto_async).init();
    // `batch` に async なジョブ `one()` と `two()` とを追加する
    batch.add(&async one());
    batch.add(&async two());
    // `wait` で `one()` と `two()` が完了するまで待つ
    batch.wait();

    testing.equal(@to(usize, 1), batch.jobs[0].result);
    testing.equal(@to(usize, 2), batch.jobs[1].result);
}

fn one() usize {
    return 1;
}

fn two() usize {
    return 2;
}

Batch

Batch は型を返す関数です。

/// 複数の async 関数 (ジョブ) をヒープアロケーションなしに並列実行します。
pub fn Batch(
    /// ジョブの戻り値型です
    comptime Result: type,

    /// 並列実行可能な最大ジョブ数です
    comptime max_jobs: comptime_int,

    /// `add` と `wait` が `async` 関数かどうかをコントロールします
    comptime async_behavior: enum {
        /// Observe the value of `std.io.is_async` to decide whether `add`
        /// and `wait` will be async functions. Asserts that the jobs do not suspend when
        /// `std.io.mode == .blocking`. This is a generally safe assumption, and the
        /// usual recommended option for this parameter.
        auto_async,

        /// Always uses the `noasync` keyword when using `await` on the jobs,
        /// making `add` and `wait` non-async functions. Asserts that the jobs do not suspend.
        never_async,

        /// `add` and `wait` use regular `await` keyword, making them async functions.
        always_async,
    },
) type

初期化用の関数が1つ、メソッドが2つ、あります。

  • init

Batchインスタンスを返します。

pub fn init() Self;
  • add

ジョブをBatchインスタンスに追加します。 もし、最大ジョブ数分、既にジョブが投入されている場合、1つのジョブが完了するまで待ちます。

引数のframe (型anyframe->Result) は、async関数のフレームポインタです。 今回は詳しく説明しませんが、要するに普通の関数ポインタではなく、async関数のフレームを渡さないといけない、ということです。

pub fn add(self: *Self, frame: anyframe->Result) void;
  • wait

全てのジョブが完了するのを待ちます。 もしジョブがエラー共用体を返す場合、最後に発生したエラーを返します。

pub fn wait(self: *Self) CollectedResult;

さて、これだけだとasync何か関係あるの?という感じなのですが、続きは次回。