スケジューラ

スケジューラはワークスティーリング設計を使用してプロセスを実行します。ワーカーはローカルdequeを維持し、アイドル時に互いからスティールします。

プロセスインターフェース

スケジューラはProcessインターフェースを実装する任意の型で動作:

type Process interface {
    Init(ctx context.Context, method string, input payload.Payloads) error
    Step(events []Event, out *StepOutput) error
    Close()
}
メソッド 目的
Init エントリメソッド名と入力引数でプロセスを準備
Step 着信イベントで状態マシンを進め、出力にyieldを書き込み
Close リソースを解放

Initmethodパラメータはどのエントリポイントを呼び出すかを指定。プロセスインスタンスは複数のエントリポイントを公開でき、呼び出し側がどれを実行するかを選択。これはスケジューラがプロセスを正しく開始していることの検証としても機能。

スケジューラはStep()を繰り返し呼び出し、イベント(yield完了、メッセージ)を渡してyield(ディスパッチするコマンド)を収集。プロセスはステータスとyieldをStepOutputバッファに書き込む。

type Event struct {
    Type  EventType  // EventYieldCompleteまたはEventMessage
    Tag   uint64     // yield完了用の相関タグ
    Data  any        // 結果データまたはメッセージペイロード
    Error error      // yieldが失敗した場合のエラー
}

構造

スケジューラはデフォルトでGOMAXPROCS個のワーカーを生成。各ワーカーはキャッシュフレンドリーなLIFOアクセス用のローカルdequeを持つ。グローバルFIFOキューは新しいサブミッションとワーカー間転送を処理。プロセスはメッセージルーティング用にPIDで追跡。

ワーク探索

flowchart TD
    W[ワーカーがワークを必要] --> L{ローカルdeque?}
    L -->|アイテムあり| LP[底からLIFOでポップ]
    L -->|空| G{グローバルキュー?}
    G -->|アイテムあり| GP[ポップ + 最大16個をバッチ転送]
    G -->|空| S[ランダムな犠牲者からスティール]
    S --> SH[犠牲者のdequeからStealHalfInto]

ワーカーは優先順位でソースをチェック:

優先度 ソース パターン
1 ローカルdeque LIFOポップ、ロックフリー、キャッシュフレンドリー
2 グローバルキュー バッチ転送付きFIFOポップ
3 他のワーカー 犠牲者のdequeから半分をスティール

グローバルからポップする際、ワーカーは1つのアイテムを取得し、最大16個をローカルdequeにバッチ転送。

Chase-Lev Deque

各ワーカーはChase-Levワークスティーリングdequeを所有:

type Deque struct {
    buffer atomic.Pointer[dequeBuffer]
    top    atomic.Int64  // 泥棒がここからスティール(CAS)
    bottom atomic.Int64  // 所有者がここでプッシュ/ポップ
}

所有者は同期なしで底からプッシュ/ポップ(LIFO)。泥棒はCASを使用して上からスティール(FIFO)。これにより所有者は最近プッシュされたアイテムにキャッシュフレンドリーにアクセスでき、古いワークはスティーラーに分配。

StealHalfIntoは1回のCAS操作で半分のアイテムを取得し、競合を削減。

適応型スピニング

条件変数でブロックする前に、ワーカーは適応的にスピン:

スピン回数 アクション
< 4 タイトループ
4-15 スレッドyield(runtime.Gosched
>= 16 条件変数でブロック

プロセス状態

stateDiagram-v2
    [*] --> Ready: Submit
    Ready --> Running: ワーカーによるCAS
    Running --> Complete: 完了
    Running --> Blocked: コマンドをyield
    Running --> Idle: メッセージ待ち
    Blocked --> Ready: CompleteYield
    Idle --> Ready: Sendが到着
状態 説明
Ready 実行待ちキュー
Running ワーカーがStep()を実行中
Blocked yield完了待ち
Idle メッセージ待ち
Complete 実行完了

ウェイクアップフラグは競合を処理:ハンドラがワーカーがまだプロセスを所有している(Running)間にCompleteYieldを呼び出すと、フラグを設定。ワーカーはディスパッチ後にフラグをチェックし、設定されていれば再キュー。

イベントキュー

各プロセスはMPSC(multi-producer, single-consumer)イベントキューを持つ:

  • プロデューサー: コマンドハンドラ(CompleteYield)、メッセージ送信者(Send
  • コンシューマー: ワーカーがStep()でドレイン

メッセージルーティング

スケジューラはrelay.Receiverを実装してメッセージをプロセスにルーティング。Send()が呼ばれると、byPIDマップでターゲットPIDを検索し、メッセージをイベントとしてプロセスキューにプッシュし、アイドルならプロセスをグローバルキューにプッシュしてウェイク。

シャットダウン

シャットダウン時、スケジューラはすべての実行中プロセスにキャンセルイベントを送信し、完了またはタイムアウトを待機。ワーカーはワークがなくなると終了。

関連項目