プロセススケジューリング
1つのCPUを多数のプロセスで“代わりばんこ”に使う仕組み。誰に・どれだけCPUを渡すかを決めるのがスケジューラの仕事。
- 1.結論:CPUは一度に1つの処理しか動かせない。それを高速で切り替えて“同時に動いて見せる”のがスケジューリング。
- 2.プリエンプティブ(途中で取り上げる)が現代OSの標準。FCFS/SJF/ラウンドロビン/優先度などの方式で“次に動かす1つ”を選ぶ。
- 3.切り替え(コンテキストスイッチ)はタダではない。応答性(待たせない)とスループット(さばく量)はトレードオフ。
なぜ必要なのか
プロセス(実行中のプログラム)は CPU を使いたがります。でも 1コアの CPU が同時に走らせられるのは 1つだけ。プロセスが CPU を待つ列(実行可能キュー / ready queue)に並んだとき、どれを次に走らせるか を誰かが決めないといけません。
- 全部を「順番に最後まで」やると、重い処理の後ろに並んだ軽い処理がいつまでも始まらない
- かといって細かく切り替えすぎると、切り替えの手間ばかり食って本来の処理が進まない
このバランスを取るのがスケジューラの役目です。ちなみに「プロセス」と「スレッド」の関係や、現代OSが実際に切り替える単位については /os/process-thread/ を参照してください(実装上は スレッド単位 でスケジュールするOSが多い)。
プロセスの状態とCPUの取り合い
スケジューリングを理解する鍵は、プロセスがずっと CPU を使い続けるわけではない、という点です。プロセスは3つの状態を行き来します。
┌──────────┐ ディスパッチ ┌──────────┐
│ Ready │ ───────────────▶ │ Running │
│ (待機列) │ ◀─────────────── │ (実行中) │
└──────────┘ プリエンプト └──────────┘
▲ │
│ I/O完了 │ I/O要求 / sleep
│ ▼
┌─────────────────────────────────────┐
│ Waiting / Blocked (I/O待ちなど) │
└─────────────────────────────────────┘
ここで重要なのは、プロセスが ディスクやネットワークの I/O を待つ間は CPU を使わない こと。その隙に別のプロセスへ CPU を回せます。だからこそ「CPUバウンド(計算中心)」と「I/Oバウンド(待ち中心)」を 混ぜて動かす と CPU を遊ばせずに済むわけです(I/O 待ちの仕組みは /os/interrupt-io/ も参照)。
プリエンプティブ と ノンプリエンプティブ
スケジューリングは「動いているプロセスを 途中で強制的に止められるか 」で大きく2種類に分かれます。
| 観点 | プリエンプティブ | ノンプリエンプティブ |
|---|---|---|
| CPUの取り上げ | OSが途中で強制的に取り上げる | プロセスが自発的に手放すまで待つ |
| きっかけ | タイマー割り込み・高優先度の到着 | 終了・I/O要求・自発的な譲渡 |
| 応答性 | 良い(待たせにくい) | 悪化しうる(長い処理に占有される) |
| 実装の複雑さ | 高い(共有データの保護が必須) | 低い(切れ目が予測しやすい) |
| 代表例 | Linux/Windows/macOS など現代の汎用OS | 古い協調的マルチタスク・一部の組込み |
現代のデスクトップ/サーバ OS は ほぼプリエンプティブ です。定期的に発生する タイマー割り込み をきっかけに OS が制御を取り戻し、「このまま続けさせるか、別のプロセスに替えるか」を判断します。これにより、1つの暴走プロセスが CPU を独占して全体を固める事故を防げます。
1コアでのマルチタスクは 本当に同時に動いているわけではありません。高速に切り替えて「同時に見せている」だけ(並行 / concurrency)。物理的に同時へ進むのは複数コアで実際に並列実行(parallelism)したときです。並行と並列は別物。混同に注意。
代表的なスケジューリング方式
「次に動かす1つ」をどう選ぶか。古典的なアルゴリズムを押さえると、現代の複雑なスケジューラの発想も読み解けます。
| 方式 | 選び方 | 長所 | 短所 / 注意 |
|---|---|---|---|
| FCFS(到着順) | 先に来た順に最後まで | 単純・公平で飢餓なし | 長い処理が先頭だと後続が待つ(コンボイ効果) |
| SJF(最短ジョブ優先) | 実行時間が短いものを先に | 平均待ち時間が理論上最小 | 実行時間を事前に知れない/長い処理が飢餓に |
| ラウンドロビン | 一定時間(タイムスライス)ずつ順番に | 応答が良く公平 | スライスが短すぎると切替コスト増 |
| 優先度 | 優先度の高いものを先に | 重要な処理を優先できる | 低優先度が飢餓に(→エイジングで救済) |
FCFS(First-Come, First-Served)
来た順に並べて、各プロセスを 最後まで 実行するノンプリエンプティブな方式。仕組みは単純ですが、先頭に長い処理が来ると後ろの短い処理がまとめて待たされます(コンボイ効果)。
SJF(Shortest Job First)
残り(または必要)実行時間が 最短 のものを先に処理します。平均待ち時間を最小化できる理論的に強い方式ですが、「これからどれだけ掛かるか」を 正確には知れない のが現実の壁。過去の実績から予測する形で近似します。プリエンプティブ版は SRTF(最短残時間優先) と呼びます。
ラウンドロビン(Round Robin)
各プロセスに タイムスライス(タイムクォンタム) という持ち時間を割り当て、使い切ったら列の最後尾へ回す方式。プリエンプティブの代表で、対話的な用途に向きます。スライスの長さが肝で——
スライスが長すぎる → FCFS に近づき、応答が悪化
スライスが短すぎる → 切り替えばかり発生し、オーバーヘッドが増える
優先度スケジューリング
各プロセスに 優先度 を付け、高いものを先に。OS は重要なシステム処理や対話的なプロセスを優先できます。ただし優先度が低いプロセスがいつまでも回ってこない 飢餓(starvation) が起きうるので、待ち時間に応じて優先度を徐々に上げる エイジング(aging) で救済します。
「高優先度なら必ず先に動く」と思い込むと危険。高優先度のプロセスが、低優先度のプロセスの握るロックを待ち、その低優先度が中優先度に割り込まれて進めない——という 優先度逆転(priority inversion) が起きると、高優先度が事実上止まります。火星探査機 Mars Pathfinder の不具合が有名で、対策は 優先度継承 など。排他制御の話は /os/concurrency-control/ を参照。
コンテキストスイッチ ── 切り替えはタダではない
プロセスを切り替えるとき、OS は止める側の状態(レジスタ、プログラムカウンタ、スタックポインタなど)を保存し、次に動かす側の状態を復元します。これが コンテキストスイッチ です。
[実行中:A] ── タイマー割り込み ──▶ Aの状態を保存
└▶ スケジューラが次(B)を選ぶ
└▶ Bの状態を復元 ──▶ [実行中:B]
この切り替え自体は 何の仕事も前に進めない純粋なオーバーヘッド。さらに切り替えで CPU キャッシュや TLB が汚れ、再び温まるまで間接的なコストもかかります。だから「細かく切り替えれば切り替えるほど良い」わけではありません。
多くのOSが実際に切り替える単位はプロセスではなく スレッド。同じプロセス内のスレッド間切り替えは、アドレス空間(ページテーブル)を共有するぶん、別プロセスへの切り替えより軽くなります。さらに軽い切り替えとして、OS を介さずユーザー空間で切り替える非同期処理/コルーチンの考え方もあります(/programming/sync-async/)。
応答性 vs スループット ── 何を最適化するか
スケジューラに「唯一の正解」はありません。何を良しとするかは用途しだいで、しかも複数の指標は 同時に最大化できないトレードオフ の関係にあります。
| 指標 | 意味 | 重視する場面 |
|---|---|---|
| 応答時間 / レイテンシ | 要求してから反応が返るまでの速さ | 対話的UI・ゲーム・Webサーバ |
| スループット | 単位時間にさばける処理の量 | バッチ処理・ビルド・データ集計 |
| 公平性 | どのプロセスにも均等に機会が回るか | マルチユーザー・共有サーバ |
| CPU使用率 | CPUを遊ばせず使い切れているか | 計算資源を絞り切りたい全般 |
例えばタイムスライスを短くすると、各プロセスがすぐ順番を得られて 応答は良く なりますが、切り替えが増えて スループットは落ちます。逆に長くすればスループットは上がるが対話の反応は鈍る。現実のOSは、対話的なプロセスには短く・計算中心のプロセスにはまとめて時間を渡す、といった 動的な調整(マルチレベルフィードバックキュー、Linux の CFS / EEVDF など)でこのバランスを取っています。
体感のキビキビ感は CPU の生クロックだけでなく スケジューラの方針 に大きく左右されます。重いビルド中でも入力が引っかからないのは、OS が対話的プロセスを優先して短く回しているから。逆に方針が悪ければ高性能CPUでも“もっさり”します。
まとめ ── どう選ぶか
- 待たせたくない(対話・サーバ) → プリエンプティブ+短めスライスで 応答性 を優先
- とにかく量をさばきたい(バッチ・ビルド) → 切替を減らして スループット を優先
- 重要処理を優先しつつ全員に機会を → 優先度+エイジング、あるいはマルチレベルフィードバックキュー
- 共通の鉄則:切り替えはタダではない。応答性とスループットは引っ張り合うので、用途に合わせて配分を決める
スケジューリングは「限られた CPU 時間を誰にどう配るか」という資源配分の問題。メモリの配り方(/os/memory-management/)と並ぶ、OS の中核的な仕事のひとつです。
OS Article
プロセススケジューリングを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
スケジューリング
比較で見る軸
難易度: intermediate / カテゴリ: OS / タグ数: 4
導入後に効く点
プリエンプティブ(途中で取り上げる)が現代OSの標準。FCFS/SJF/ラウンドロビン/優先度などの方式で“次に動かす1つ”を選ぶ。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- intermediate
- カテゴリ
- OS
- タグ数
- 4
判断チェックリスト
- 自社の用途が「スケジューリング / プロセス」に近いか確認する。
- 強みである「結論:CPUは一度に1つの処理しか動かせない。それを高速で切り替えて“同時に動いて見せる”のがスケジューリング。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。