この記事では、Webアプリケーションの代表的な処理モデルについて書く。
- イベントループ
- スレッド
- プロセス
各処理モデルの概要
イベントループモデル(非同期・シングルスレッド)
- 特徴:1つのスレッドで、イベント(非同期IOなど)を順に処理
- 代表例:Node.js、Deno、JavaScript(ブラウザ)
メリット
- メモリ効率が良い(スレッドやプロセスを大量に作らない)
- IO待ちを他の処理に活用できる
デメリット
- 重い計算(CPUバウンド)でブロックしやすい
スレッドモデル(マルチスレッド)
- 特徴:1プロセスの中で、複数のスレッドが並行に動作
- 代表例:Java、Python、Go(内部的にスレッドスケジューラ)
メリット
- CPUバウンド処理に強い(マルチコア活用可能)
デメリット
- スレッドごとのリソース消費や、競合状態の管理が必要
プロセスモデル(マルチプロセス)
- 特徴:各リクエストを別プロセスで処理。完全に分離されている
- 代表例:PHP(FPM)、Ruby(複数Pumaプロセス)、Sidekiq(マルチプロセス構成)
メリット
- 安定性が高い(他の処理の影響を受けにくい)
デメリット
- メモリ効率が悪い(プロセスごとに環境を持つ)
言語ごとの処理モデルと向き・不向き
| 言語 | 処理モデル | IOバウンド | CPUバウンド | 備考 |
|---|---|---|---|---|
| Node.js | イベントループ(非同期) | ◎ | △ | IO特化、重い計算処理は注意 |
| Go | goroutine + M:Nスレッド | ◎ | ◎ | 軽量スレッドで並列・並行処理が得意 |
| Ruby(MRI) | スレッド+GIL(制限あり) | ○ | △ | GILによりCPU処理は実質シングルスレッド |
| PHP(FPM) | プロセス(1リクエスト=1プロセス) | ○ | △ | プロセス分離で安定だがオーバーヘッド大 |
| Java | マルチスレッド | ◎ | ◎ | JVMレベルでのスレッド最適化 |
| Python(CPython) | スレッド+GIL(制限あり) | ○ | △ | RubyのMRIと同様にGILの制約あり |
各処理モデルの実装上の注意点
イベントループモデル
- 単一スレッド:真の並列処理は不可能
- ノンブロッキングIO:同期処理はイベントループをブロックする
- CPUバウンド回避:重い計算はWorker Threadsや外部プロセスに委譲
スレッドモデル
- 競合状態:共有メモリへの同時アクセス制御が必要
- デッドロック:複数ロックの取得順序に注意
- メモリオーバーヘッド:スレッドあたり約1-8MBのスタック領域
プロセスモデル
- プロセス間通信:IPCやファイルシステム経由での連携
- メモリ使用量:各プロセスが独立したメモリ空間を持つ
- 起動コスト:プロセス作成はスレッド作成より重い
まとめ
各処理モデルには一長一短があり、アプリケーションの特性や要件に応じて適切なモデルを選択することが重要である。IOバウンドな処理が多い場合はイベントループモデル、CPUバウンドな処理が多い場合はスレッドモデルやプロセスモデルが適していると考えられる。また、言語ごとの特性も考慮すると良い。