Event Loop とは?シングルスレッドの並行性
event loop は、キューから次の準備できたイベントを繰り返し取り出して最後まで実行することで、1 つの thread が多くのタスクをさばけるようにする runtime の仕組みです。
Node.js やブラウザのような runtime は、あなたのコードにとってはシングルスレッドですが、ブロックせずに何千ものネットワーク接続をさばきます。その仕掛けが event loop です。イベント(timer の発火、データの到着、promise の解決)を待ち、関連する callback を実行して次へ進むループです。async/await と callback の背後にあるエンジンです。
loop がどう動くか
event loop は保留中の作業のキューを確認します。実行準備のできた callback、経過した timer、完了した I/O です。次のものを取り、最後まで実行し、繰り返します。callback の実行中は他に何も動かないため、各タスクは短くあるべきです。
なぜ 1 つの thread がこれほどできるのか
サーバーの作業の多くは I/O バウンドです。ネットワークやディスクを待ちます。event loop は I/O 操作を開始して OS に引き渡し、他の作業へ移り、後で結果に戻ります。アイドルな待機が thread をブロックすることは決してありません。
loop をブロックするもの
- main thread での長い同期ループや重い計算。
- インラインで待つ同期のファイルやネットワーク呼び出し。
- 制御を譲らずに行う大きな JSON のパースや crypto。
- 制御を loop へ速やかに返さないあらゆるもの。
ブロックの危険
すべてが 1 つの thread を共有するため、1 つの遅い同期タスクがプログラム全体を凍りつかせます。他の callback は動かず、リクエストはさばかれません。作業を非同期に保つか、CPU の重いタスクを worker へ移すことで、loop の応答性を保ちます。
簡単な例
setTimeout(fn, 0) は fn をすぐには実行しません。現在の同期コードが終わった後、event loop の後のターンで実行するよう fn をキューに入れます。
CI における event loop
event loop の runtime 上の test runner は、promise が決して解決しなかったり handle が開いたままだったりするとハングし、job を timeout まで停滞させます。Latchkey は job の timeout を強制するため、詰まった event loop は速やかに打ち切られ、本当に一時的に見える失敗だけを retry します。
重要なポイント
- event loop は、キューからイベントを処理することで 1 つの thread が多くのタスクをさばけるようにします。
- アイドルな待機で決してブロックしないため、I/O バウンドの作業に秀でています。
- 重い同期処理は loop をブロックし、プログラム全体を凍りつかせます。