LASSIC Media らしくメディア

2026.07.31 らしくコラム

イベントループとは|非同期処理をさばく仕組み

システム開発の要件定義や技術選定の場で、「イベントループ」という言葉を目にすることがあります。同時に多数の利用者からリクエストが届くWebサービスやAPIの設計では、この仕組みへの理解が、性能要件や委託先への確認事項を整理するうえで役立つはずです。

この記事では、発注担当者やプロジェクトマネージャーの方に向けて、イベントループの基本的な考え方を整理します。あわせて、複数のスレッドで処理を並べる方式との違いや、発注・レビューの際に押さえておきたい観点も取り上げます。

空港の手荷物カルーセルのイメージ。タスクが順に回ってきて一つずつ処理されるイベントループの比喩

この記事のポイント

  • イベントループは、一つの処理の流れ(シングルスレッド)で、待ち時間の長い処理を効率よくさばく仕組みです。
  • 複数のスレッドを用意して並行に処理を進める方式とは異なる考え方で、I/O待ちが中心の処理と相性がよい仕組みといえます。
  • 発注・レビューの場面では、重い計算処理を別に逃がす設計になっているかどうかの確認が欠かせません。

イベントループとは

イベントループとは、一つの処理の流れ(シングルスレッド)で、順番待ちのタスクを次々に取り出しては実行し続ける仕組みです。この仕組みにより、待ち時間の長い処理を効率よくさばけます。複数のスレッドで並行に処理を進めるスレッドプールとは対照的な考え方で、一つの流れの中で待ち時間を活用する点に違いがある仕組みだといえるでしょう。

窓口が一つしかない受付を思い浮かべると、イメージがつかみやすいかもしれません。受付担当者は、来客が書類を記入する間ただ待つのではなく、その間に次の来客の案内を進め、書類ができあがった順に対応を再開します。イベントループも同様に、一人の担当者が、複数の待ち時間を並行してさばいているようなものです。

この仕組みは、Webブラウザ上で動くJavaScriptや、それをサーバー側で動かすNode.jsの中核として使われています*1*2。GUIアプリケーションでは、利用者の操作やシステムからの通知を待ち受ける仕組みとしても、古くから採用されてきました*3

非同期の入出力(I/O)を中心に据えたサーバーソフトウェアでも、同様の考え方が根づいているのです。ネットワークやディスクへの問い合わせを待つあいだに、他の処理を進められる点が評価されてきたのです。実際にどのような場所で動いているのか、代表的な環境を整理すると次のようになります。

利用される場面 役割の例
JavaScript実行環境(ブラウザ) 利用者の操作やタイマーへの応答を一つのスレッドで処理する*1
Node.js(サーバーサイド) ネットワークやファイルの入出力を待つ間に、他のリクエストを処理する*2
GUIアプリケーション ウィンドウ操作やシステムからの通知を待ち受けて処理する*3
非同期I/O主体のサーバーソフトウェア 同時接続をスレッド数の少ない構成でさばく
デスクトップ・モバイルアプリの画面描画 画面の描画と利用者の操作への応答を一つのスレッドで処理する*3

いずれの環境にも共通するのは、応答待ちの処理を一つのスレッドで回し続けるという発想です。個別の実装は異なっても、待ち時間を無駄にしないという狙いは共通しているといえるでしょう。

発注担当者にとって重要なのは、採用予定の技術がこの仕組みを土台にしているかどうかを、事前に把握しておくことです。JavaScript系の技術を選ぶ場合、性能特性はおおむねイベントループの挙動に左右されると考えてよいでしょう。

シングルスレッドで動くことには、待ち時間の活用以外にもう一つの利点があります。一つの処理が完了するまで、別の処理に割り込まれることがないため、同じデータに複数の処理が同時に触れて不整合が起きる、という事態を避けやすいのです*1。複数のスレッドを扱う設計で気を配る排他制御の手間が、この点では小さくて済みます。

なぜこの仕組みが選ばれるか

複数の利用者から同時にリクエストが届くシステムを作る場合、対応の仕方は大きく二つに分かれます。一つは、リクエストごとにスレッドを割り当てて並行に処理する方式です。もう一つが、一つのスレッドでイベントループを回し、待ち時間の間に次のタスクへ進む方式になります。

スレッドを増やす方式は、CPUを使う処理を並行に進めやすい一方、スレッドの数だけメモリを消費し、切り替えの負荷も増えていきます。イベントループ方式では、ネットワークやディスクの応答待ちの間に他のタスクを進めるため、スレッド数を抑えたまま同時接続を多数さばけるのが特徴でしょう。

チャットツールやリアルタイム通知を扱うサービスでは、常時接続を維持する利用者の数が膨らみやすい傾向があります。こうしたサービスをスレッドを増やす方式で作ると、早い段階でリソースの上限に近づいてしまいます。イベントループ方式であれば、接続を維持したまま、他の利用者への応答を進められる余地が生まれるのです。

先ほどの受付の例でいえば、スレッドを増やす方式は、来客が増えるたびに窓口を追加していくやり方に近いといえるでしょう。窓口を増やせば同時に対応できる人数は増えますが、担当者を配置する分だけ、人件費や管理の手間もかさんでいきます。イベントループ方式は、一人の担当者が段取りよく複数の来客をさばくやり方に近く、窓口を増やさなくても同時に多数の来客をさばける場合があるのです。窓口を増やす方式では、来客の少ない時間帯でも配置した担当者の分だけ人件費がかさむ、という運用面の課題も生まれがちです。

たとえば、リクエストのたびに新しいスレッドを立ち上げる設計では、同時アクセスが増えるほどメモリ使用量と切り替えの手間が積み上がっていきます。イベントループ方式なら、この積み上がりを避けながら、応答待ちの時間を他の処理に回せるのが利点です。

性能を議論するときは、「レイテンシ(1件あたりの応答時間)」と「スループット(単位時間あたりに処理できる件数)」を分けて考えると整理しやすくなります。イベントループ方式は、スループットを高めやすい一方、個々の処理そのものが重くなると、レイテンシが伸びやすいという特徴を持っています。この特性は、必要なサーバー台数の見積もりにも影響してくるでしょう。

観点 スレッドを増やす方式 イベントループ方式
処理の並べ方 複数スレッドで同時に実行 一つのスレッドで順番に処理
得意な処理 CPUを使う重い計算 ネットワーク・ディスク待ちが多い処理
リソースの使われ方 スレッド数に応じてメモリ・切り替え負荷が増える スレッド数を抑えたまま同時接続をさばける
向くシステム例 画像処理・数値計算などの並列処理基盤 Webサーバー・APIサーバー・チャット基盤
代表的な実装例 従来型のJavaサーブレットコンテナなど Node.js、Nginxなど

どちらか一方がすぐれているわけではなく、扱う処理の性質によって向き不向きが分かれます*2。発注時には、想定する処理がどちらの特性に近いかを確認しておくと、システム構成の妥当性を判断しやすくなるはずです。実務では、どちらか一方だけを使うとは限りません。イベントループを軸にしながら、重い処理だけを別のスレッドプールに逃がす、組み合わせ型の設計もよく採られるでしょう。内部でどのようにタスクを処理しているのか、次の章でもう少し踏み込んで見ていきましょう。

タスクキューとコールバックの仕組み

この仕組みを、もう少していねいに見ていきましょう。処理すべきタスクは、いったん「タスクキュー」と呼ばれる待ち行列に積まれます。イベントループは、実行中の処理が一段落した合間を見て、キューの先頭からタスクを一つずつ取り出し実行するのです*1

コールスタックとタスクキューの関係

実行中の処理を管理する「コールスタック」は、関数の呼び出しと終了を後入れ先出し(LIFO)で管理する仕組みです*1。これに対し、非同期処理の完了後に控えるコールバックを並べるタスクキューは、先入れ先出し(FIFO)の待ち行列になっています。イベントループは、コールスタックが空になったタイミングを見て、タスクキューから次の処理を取り出しているのです。

タスクキューはさらに、優先度の高い「マイクロタスク」と、通常の「タスク」に分けて扱われます*1。マイクロタスクが残っている間は、通常のタスクより先に処理が進みます。こうした優先順位が組み込まれている点も、あわせて知っておくとよいでしょう。

処理の順番を分けるフェーズという考え方

Node.jsの実装では、イベントループの内部が複数の段階(フェーズ)に分かれて進みます*2。タイマー・保留中の処理・I/Oの実行・setImmediateといった段階を、順番に繰り返す構成です。発注側が細部まで把握する必要はありません。ただし、処理の実行タイミングにこうした順序が組み込まれているという点は、仕様や不具合の原因を確認する際の手がかりになります。

図
図:タスクキューの処理をイベントループが1つずつ取り出して実行し、I/O待ちの処理は完了後にコールバックとしてキューへ戻る

取り出したタスクがネットワークやディスクへの問い合わせのように時間のかかる処理であれば、その場では終わらせず、OS側の仕組みに処理を預けます*2。応答が返ってきた時点で、続きの処理はコールバックとしてキューに積み直され、イベントループが順番に取り出して実行を再開する流れです。この受け渡しをOS側に任せることで、応答を待つためだけの専用スレッドを割り当てずに済んでいるのです。

この一連の流れを支える前提が、ノンブロッキングI/O(処理を止めずに次へ進める入出力の方式)になります。一つのタスクが応答を待つあいだも、ループそのものは止まらず、次のタスクを取り出し続けるのです。

近年のJavaScriptでは、Promiseやasync/awaitといった書き方が普及しています*1。これにより、コールバックを何重にも重ねなくても、非同期の処理を分かりやすく記述できるようになりました。ただし、記法が変わっても、内部で動いているのはここまで説明したタスクキューとイベントループの仕組みそのものです。発注時の見積もりでこうした書き方の違いが話題になった場合も、土台の理解があれば判断に困りません。外部のAPIやデータベースへの問い合わせするコードでは、応答を待つ間に他の処理を進められるかどうかが、非同期の書き方次第で変わってくるのです。

ここまで見てきたタスクキュー、イベントループ、I/O待ちの領域は、常にこの三者が組み合わさって処理を回し続けています。次の章では、この仕組みがどのような処理に向き、どのような処理には向かないのかを整理します。

向いている処理・向かない処理

イベントループが力を発揮するのは、ネットワーク通信やファイルアクセスのように、応答を待つ時間が長い処理です。待ち時間の間に別のタスクを進められるため、少ないスレッドで同時に複数の処理を進められます。

逆に不得手なのが、画像の変換や大量データの集計のように、CPUを長時間占有する重い計算です。こうした処理を一つのタスクとしてそのまま流すと、ループ全体が詰まり、他の待機中の処理が進まなくなります。応答が一時的に遅れる、あるいは止まって見える状態が起こりうるのです。

たとえば、利用者からの画像アップロードをその場で加工して返す処理を、そのままイベントループの中に書き込んだとします。加工が終わるまで、他のリクエストへの応答はすべて止まってしまいます。加工の部分だけを別のスレッドやワーカーへ切り出しておけば、ほかのリクエストへの応答を止めずに済むはずです。

月次のレポート集計処理を、日中のリクエスト処理と同じイベントループの中に組み込んだ場合も、同様の問題が起こります。集計が終わるまでのあいだ、他の利用者への応答がすべて滞ってしまうためです。夜間バッチとして切り出す、あるいは別のジョブとして走らせるといった設計上の工夫が求められます。

この弱点への対処として、重い計算は別のスレッドやプロセス、あるいは別のサービスへ切り出す設計がよく採られます。イベントループ自体は、細切れの処理を軽快に回すことに向いた仕組みであり、重い計算までを一つの流れの中で完結させる設計には向いていないといえるでしょう。

観点 I/O待ちが中心の処理 CPUを長時間占有する処理
ループへの影響 待っている間に他のタスクを進められる 完了するまでループ全体が止まる
利用者への影響 応答は保たれやすい 応答が遅れる、または止まって見える
基本的な対処 そのままイベントループに任せてよい 別のスレッドやサービスへ切り出す

こうした詰まりは、外形的な死活監視だけでは気づきにくく、利用者からの問い合わせで発覚するケースも見られます。設計段階から、処理の種類ごとに置き場所を分けておく発想が欠かせません。

処理を設計する際の目安は、比較的シンプルです。応答を待つだけの処理はイベントループに任せ、計算そのものに時間がかかる処理は別の場所に逃がす、という切り分けを基本方針にするとよいでしょう。

応答が遅れる状態が続くと、利用者が離脱するきっかけになりかねません。とくに初めて利用する顧客は、最初の体験で見切りをつけやすいものです。

運用の現場では、イベントループの遅延そのものを監視指標として計測し、詰まりの兆候を早期に把握する工夫も見られます。監視の仕組みがあれば、利用者からの問い合わせより先に、社内で異常に気づける体制をつくれます。発注時には、こうした監視の仕組みを運用保守の範囲に含めるかどうかも、あわせて確認しておくとよいでしょう。

発注・レビューで押さえる点

イベントループを採用したシステムを発注・レビューする際は、次の5点を確認しておくと、後々のトラブルを避けやすくなります。

重いCPU処理を別に逃がす設計か

見積もりや設計書を確認する段階で、画像処理・帳票生成・大量データの集計といった重い計算がどこで実行されるかを尋ねておきましょう。同じイベントループの中で処理する設計になっていると、利用者数が増えたときに応答遅延が起きやすくなります。別のワーカーやサービスへ切り出す設計になっているかどうかが、確認のポイントです。帳票のPDF生成をリクエスト処理の中で同期的に行っていないか、といった具体的な質問も有効でしょう。

想定する同時接続数のすり合わせ

イベントループ方式は、少ないスレッドで同時接続を多数さばける半面、想定を超えた負荷がかかると、待ち行列そのものが伸び続けます。ピーク時にどの程度の同時接続数を想定しているか、委託先とすり合わせておくことが望ましいでしょう。確認を怠ると、繁忙期のアクセス集中時に、応答の遅れが利用者の体験に直結しかねません。見積書に想定同時接続数を明記してもらうと、後から認識の食い違いに気づく事態を防ぎやすくなります。受け入れテストの段階で、想定に近い負荷をかけて応答時間の変化を確認しておくと、本番投入後の想定外を減らせるでしょう。

応答遅延の要件(SLA)を先に決める

どこまでの応答時間を許容するのかという要件は、システムの構成そのものに影響します。応答遅延の上限を先に決めておけば、重い処理の切り出し方や、サーバー構成の見直しが必要かどうかを、委託先と具体的に話し合えるでしょう。契約書や仕様書に応答時間の基準値を明記しておくと、完成後の検収でも判断の物差しになります。

エラー処理とタイムアウトの設計

I/O待ちの処理は、応答が返ってこない場合の扱いも設計に含める必要があります。タイムアウトの時間や、失敗した際の再試行・エラー通知の仕組みが用意されているかどうかは、レビューの段階で確認しておきたい項目です。契約前に、失敗時のログ取得やアラート通知の有無も合わせて確認しておくと、後の運用がしやすくなります。

実装・保守を担当するエンジニアのスキル

非同期の処理は、処理の呼び出し元をたどるスタックトレース(エラー発生までの処理の経路)が、直感的に追いにくくなる面があります。委託先のエンジニアが、非同期処理特有の設計パターンやデバッグ手法に習熟しているかどうかも、確認しておきたいポイントでしょう。実績や過去の担当案件を尋ねる際に、あわせて聞いておくと判断の助けになります。

確認事項 見るべきポイント
重い処理の切り出し 画像処理・帳票生成などが同じループの中で処理されていないか
想定同時接続数 ピーク時の想定値を委託先とすり合わせているか
応答遅延要件(SLA) 応答時間の基準値を仕様書に明記しているか
タイムアウト設計 再試行・エラー通知の仕組みが用意されているか
担当エンジニアのスキル 非同期処理特有のデバッグ経験があるか

これらの確認は、契約前の要件定義や見積もり比較の段階で行うほど効果があります。実装が進んでから設計を作り直すよりも、初期段階で認識をそろえておくほうが、手戻りを抑えられるからです。委託先との対話を通じて認識をそろえておくことが、完成後のトラブルを防ぐ近道になるでしょう。

まとめ

ここまでの内容を、5つの要点に整理します。

  • イベントループは、一つの処理の流れで待ち時間の長い処理を効率よくさばく仕組みである。
  • 複数のスレッドを増やす方式とは異なり、少ないスレッドのまま同時接続を多数さばける。
  • タスクキューに積まれた処理をループが順に取り出し、I/O待ちはコールバックとして後から戻る。
  • CPUを長時間占有する重い計算には不向きで、別のスレッドやサービスへの切り出しが必要になる。
  • 発注・レビューでは、重い処理の切り出し設計・想定同時接続数・応答遅延要件・タイムアウト設計・担当エンジニアのスキルの5点を確認する。

LASSICに相談するメリット

どこまでをイベントループに任せ、どこから別の処理へ逃がすかは、性能要件と業務要件の両方を見ないと判断しづらい設計事項です。「同時アクセスが増えても応答を落としたくないが、どこにボトルネックが出るか判断しにくい」「重い処理の切り出し方が分からない」といった悩みは珍しくありません。LASSICでは、要件定義の段階からアーキテクチャの方針づくり、実装、公開済みシステムの見直しまでを一貫してご相談いただけます。既存システムの応答遅延を調査し、ボトルネックの切り分けから支援することも可能です。まずは現行構成の整理からでも対応が可能です。お気軽にお声がけください。

よくある質問

イベントループとスレッドプールは、どちらが優れていますか。

どちらか一方が優れているわけではなく、扱う処理の性質によって向き不向きが分かれます。イベントループは、ネットワークやディスクの応答待ちが中心の処理と相性がよく、少ないスレッドで同時接続を多数さばけます。一方でCPUを長く使う重い計算は、複数のスレッドで並行に進める方式のほうが得意です。実際のシステムでは、イベントループを軸にしつつ、重い処理だけをスレッドプールに任せる組み合わせもよく見られます。発注時は、どちらか一方に決めつけず、扱う処理の内訳を洗い出すところから始めるとよいでしょう。

重い計算をイベントループの中で動かすと、何が起こりますか。

一つの重い計算がループを占有している間、ほかの待機中のタスクは実行に進めません。利用者から見ると、応答が遅れる、あるいは一時的に止まって見える状態に陥るのです。この影響を避けるため、重い計算は別のスレッドやプロセス、別のサービスへ切り出す設計がよく採られます。関係のない画面まで固まって見える点が、利用者からの問い合わせにつながりやすい部分です。

ノンブロッキングI/Oとは、どのような仕組みですか。

処理を止めずに次のタスクへ進める入出力の方式です。ネットワークやディスクへの問い合わせを送った後、応答を待たずに他のタスクを進め、応答が返ってきた時点でコールバックとして処理を再開します。イベントループを支える前提の一つといえるでしょう。これに対して、応答が返るまで次の処理へ進まない方式が、ブロッキングI/Oと呼ばれるものです。

イベントループは、どのようなシステムで使われていますか。

Webブラウザ上のJavaScriptや、それをサーバー側で動かすNode.js、GUIアプリケーションなどで使われています。非同期の入出力を中心に据えたサーバーソフトウェアでも、同様の考え方が根づいているのです。いずれも、応答待ちの時間を活用して処理を進めたい場面で選ばれてきました。発注時には、採用予定の言語やフレームワークがこの仕組みを土台にしているかどうかを確認しておくとよいでしょう。

著者:テレリモ総研編集部 鈴木 亮佑

LASSICでは、国内ニアショア開発体制を活かし、非同期処理を前提としたシステムのアーキテクチャ方針づくりやサーバー構成の見直しを支援します。実装から、公開済みシステムの改善までを一貫して任せられる体制です。要件定義の段階から実装、テスト、リリース後の運用・保守まで、工程を分けずに任せられる点も特徴でしょう。国内のエンジニアが直接ヒアリングを担当するため、性能要件のすり合わせもスムーズに進みます。同時アクセス増加への対応や応答遅延の改善でお困りの際も、ご相談いただけます。


システム開発・アーキテクチャ設計のご相談はLASSICへ

元請(プライムベンダー)として、要件整理からご提案・開発・保守までお手伝いします。まずはお気軽にご相談ください。

無料相談はこちら

ご不明な点はお問い合わせフォームからもご連絡いただけます。

出典


View