- 技術 💻
マルチタスクとは|OSの4ミリ秒の切り替えを実測・人の作業との違い
結論
マルチタスクとは、複数の作業(タスク)を同時に進めることです。コンピューターでは、OS が1つの CPU を数ミリ秒ずつ順番に別の処理へ切り替え、たくさんのアプリが同時に動いているように見せる仕組みを指します。本当に同時に計算するのは CPU のコアが複数あるとき(マルチコア・並列処理)で、マルチタスクとは別の言葉です。人の作業でいうマルチタスクも、実際には「切り替え」の連続で、切り替えるたびに手間がかかる点はコンピューターと同じです。
この記事でわかること
- ふだんの意味(人の作業)と IT の意味(OS・CPU)の違いと、マルチコア・並列処理・並行処理との関係
- 2コアの Linux で計算を1〜8個同時に動かし、約4ミリ秒ごとの切り替え・nice 値による配分・切り替えのコストを測った実物
- プリエンプティブと協調的マルチタスクの違いを Python と Node.js で再現した結果と、自分のパソコンで確かめる方法
この記事で実際に動かしたもの:2コア・メモリ 8GB の Linux(Ubuntu 24.04、カーネル 6.18)で、gcc で作った計算だけを続ける小さなプログラムを1〜128個同時に動かし、CPU の使用率・切り替えの回数(/proc の ctxt)・1回の持ち時間・nice 値ごとの配分・切り替え1回あたりの時間・待ち時間の遅れを測りました。協調的マルチタスクは Python の asyncio と Node.js のタイマーで再現しています。
「マルチタスク」は、仕事の進め方の話として使われることも、パソコンやスマホの仕組みの話として使われることもある言葉です。どちらも「1つの頭(CPU)で複数の作業をこなす」という点は同じで、仕組みを知ると人の作業の進め方にも置き換えて考えられます。最初に、OS がどう切り替えているかを図で示します。
flowchart TD
T[タイマー割り込み<br>数ミリ秒ごと] --> S[スケジューラーが<br>次の処理を選ぶ]
S --> A[選ばれた処理を<br>持ち時間だけ実行]
A --> W[ほかの処理は<br>順番待ち・入力待ち]
W --> T
よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| マルチタスクとは | 複数の作業を同時に進めること。OS では CPU を短い時間で切り替えて同時に動いているように見せる仕組み | マルチタスクとは(ふだんの意味とITの意味) |
| マルチタスクとマルチコアの違い | マルチタスクは「切り替えて同時に見せる」、マルチコアは「計算する部品が複数ある」。2コアで計算4個は1個あたり約46%ずつ | マルチタスクとマルチコア・並列・並行の違い |
| OS は何秒ごとに切り替えるか | OS と設定しだい。手元の Linux では約4ミリ秒、Windows は Microsoft の説明で約20ミリ秒 | OSのマルチタスクの仕組み |
| プリエンプティブと協調的の違い | OS が強制的に取り上げるか、処理が自分で譲るか。譲らない処理があると、協調的な方式では全体が1秒止まった | プリエンプティブと協調的マルチタスクの違い |
| コンテキストスイッチとは | 処理を切り替えるときに、途中の状態を保存して別の処理の状態を戻す作業。同じコアで1回あたり約1.5マイクロ秒 | コンテキストスイッチとは |
| 自分のパソコンのコア数を確かめたい | Windows はタスク マネージャーの「パフォーマンス」→「CPU」、Linux は nproc、ブラウザーは navigator.hardwareConcurrency |
自分のパソコンでマルチタスクを確かめる |
| 人のマルチタスクは効率的か | 複雑な作業ほど切り替えで時間を失う、というのが心理学の研究の見方。米国心理学会は生産的な時間の最大40%を失うという研究者の見積もりを紹介している | 人のマルチタスク |
| マルチタスクが苦手なときのコツ | 同時にやらず、時間を区切って1つずつ。割り込みはメモして後で。OS の優先度と持ち時間の考え方と同じ | 人のマルチタスク |
確認環境:Ubuntu 24.04.5 LTS、Linux カーネル 6.18(CONFIG_HZ=250、スケジューラーは EEVDF)、Intel Xeon 2.10GHz の2コア(1コアあたり1スレッド、nproc は 2)、メモリ 8GB の仮想マシンで確かめました。計算だけを続けるプログラム・時間の空白を記録するプログラム・パイプで1バイトを往復させるプログラム・1ミリ秒ずつ眠って起きる遅れを測るプログラムを gcc 13.3.0(-O2)で作り、作業用のフォルダーの中だけで動かしています。コアの指定は taskset、優先度は nice、状態は ps・top・vmstat・/proc/<PID>/status・/proc/<PID>/sched・/proc/stat で読みました。協調的マルチタスクは Python 3.13.18 の asyncio と Node.js 22.23.4 で再現し、ブラウザーの値は Chromium 153.0.8010.12(Chrome for Testing のヘッドレス版)で確かめました。同じマシンでほかの作業も動いていたため、測った値には揺れがあり、主な表には測定時の load average(実行待ちの数の平均)を添えています。Windows・Mac の画面と項目名、Linux スケジューラーの設計は、Microsoft サポート・Microsoft Learn・Apple サポート・Linux カーネルの公式ドキュメント・man ページで確かめた範囲だけを書きました。人のマルチタスクは米国心理学会(APA)の公開資料の範囲です。外部のサービスには接続していません。図は mermaid-cli で描画を確かめています(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「マルチタスクとは|OSの4ミリ秒の切り替えを実測・人の作業との違い」
マルチタスクとは(ふだんの意味とITの意味)
この節では、マルチタスクという言葉の成り立ちと、場面ごとに指すものの違いが分かります。
マルチタスク(multitask)は、multi(複数の)と task(作業・仕事)を組み合わせた言葉で、「複数の作業を同時に進めること」を意味します。反対の言葉はシングルタスク(1つの作業に集中して進めること)です。もとはコンピューター用語で、1台のコンピューターが複数のプログラムを同時に動かす仕組みを指していました。そこから、人が電話をしながらメールを読む、会議中に議事録を書く、といった働き方にも使われるようになりました。
同じ言葉でも、場面によって指すものが違います。最初に整理しておくと、検索して出てくる記事の話がかみ合わない理由が分かります。
| 場面 | マルチタスクが指すもの | 例 | 実際に起きていること |
|---|---|---|---|
| ふだんの言葉(人の作業) | 複数の仕事を同時に、または細かく切り替えながら進めること | 電話しながらメールを打つ、料理しながら洗濯する | 注意を向ける先を素早く切り替えている。切り替えるたびに手間がかかる |
| OS(Windows・macOS・Linux・iOS・Android) | 複数のプログラム(プロセス・スレッド)を同時に動かす仕組み | 音楽を流しながらブラウザーと表計算を使う | OS が CPU の使える時間を細かく分け、順番に割り当てている |
| CPU(マルチコア) | マルチタスクとは別の言葉。計算する部品(コア)が複数あること | 4コア・8コアの CPU | コアの数だけ本当に同時に計算できる。コアより処理が多ければ、やはり切り替える |
| スマホ・タブレットの画面 | アプリを素早く切り替えたり、並べて表示したりする機能の呼び名 | アプリの切り替え画面、2つのアプリを並べる表示 | 画面の使い方の話。裏では OS のマルチタスクが動いている |
| 機械学習 | 「マルチタスク学習」。1つのモデルに複数の課題を同時に学ばせる手法 | 1つのモデルで分類と位置の推定を同時に学ぶ | OS のマルチタスクとは関係のない、別の専門用語 |
この記事では、主に OS のマルチタスクを実物で確かめ、最後に人の作業のマルチタスクと比べます。OS では、CPU が処理する仕事の単位を「タスク」と呼びます。Linux ではプロセスやスレッドがこれに当たり、Windows ではスレッドが CPU の時間を割り当てられる単位です。
マルチタスクがない時代
1つのプログラムが終わるまで次を始められない
ディスクや入力を待つ間も CPU は空いたまま
画面で別のアプリに切り替えるには、今のアプリを終える
マルチタスクの OS
待っている処理を脇に置き、その間に別の処理を動かす
CPU の時間を数ミリ秒単位で配り、同時に動いて見える
1つが止まっても、ほかのアプリは操作できる
マルチタスクとマルチコア・並列・並行の違い(2コアで実測)
この節では、「同時に動いて見える」マルチタスクと、「本当に同時に計算する」マルチコア・並列処理の違いが、実際の処理時間で分かります。
CPU のコアが2つなら、本当に同時に計算できるのは2つまでです。3つ目からは、OS が時間を区切って順番に動かします。これを確かめるため、1個だけなら約1.5秒で終わる計算を、1個・2個・4個・8個と同時に始めて、それぞれが終わるまでの時間(経過時間)と、実際に CPU を使った時間を測りました。
/* spin.c:決まった回数の計算をして、経過時間・CPU時間・切り替え回数を表示する */
for (long i = 0; i < n; i++) x += i * 2654435761u;
getrusage(RUSAGE_SELF, &r); /* ru_nvcsw:自分から譲った回数、ru_nivcsw:取り上げられた回数 */
for N in 1 2 4 8; do
for i in $(seq $N); do ./spin 3000000000 & done; wait
done
## N=1
pid=2248 wall=1.54s cpu=1.48s cpu/wall=96% vol=0 invol=222 lastcpu=1
## N=2
pid=2272 wall=1.59s cpu=1.36s cpu/wall=85% vol=0 invol=257 lastcpu=1
pid=2273 wall=1.60s cpu=1.36s cpu/wall=85% vol=0 invol=356 lastcpu=0
## N=4
pid=2338 wall=2.80s cpu=1.30s cpu/wall=46% vol=0 invol=374 lastcpu=1
pid=2339 wall=3.02s cpu=1.38s cpu/wall=46% vol=0 invol=521 lastcpu=0
pid=2340 wall=2.78s cpu=1.28s cpu/wall=46% vol=0 invol=646 lastcpu=1
pid=2341 wall=2.81s cpu=1.33s cpu/wall=47% vol=0 invol=395 lastcpu=1
## N=8
pid=2379 wall=5.75s cpu=1.38s cpu/wall=24% vol=0 invol=478 lastcpu=0
(以下7行は wall=5.42〜5.75s、cpu/wall=24〜25%)
| 同時に動かした数 | 全部終わるまで | 1個あたりの CPU 使用率 | 起きていること |
|---|---|---|---|
| 1個 | 1.54秒 | 96% | 1つのコアをほぼ独占 |
| 2個 | 1.61秒 | 85% | 2つのコアで1個ずつ。並列に計算するので時間はほぼ同じ |
| 4個 | 3.03秒 | 46〜47% | コア1つを2個で分け合う。マルチタスクで時間は約2倍 |
| 8個 | 5.76秒 | 24〜25% | コア1つを4個で分け合う。時間は約4倍 |
2個までは、1個のときとほぼ同じ時間で終わりました。コアが2つあるので、2個の計算は本当に同時(並列)に進みます。4個にすると、それぞれの計算の量は変わらないのに、終わるまでの時間は約2倍になりました。CPU を使った時間(cpu)はどれも約1.3〜1.4秒で同じなので、「遅くなった」のではなく「順番待ちの時間が増えた」ことが分かります。2個のときの85%は、同じマシンのほかの作業にも時間を譲ったためです。
この違いは、言葉としては次のように整理されます。
1マルチタスク
OS が複数の処理を同時に動かす仕組み。コアが1つでも、短い時間で切り替えて同時に見せる。
2マルチコア
CPU の中に計算する部品(コア)が複数あること。部品の話で、仕組みの名前ではない。
3並列処理(parallel)
複数の処理を、複数のコアで本当に同じ瞬間に計算すること。上の実測の「2個」がこれ。
4並行処理(concurrent)
複数の処理を、途中で切り替えながら同じ期間に進めること。上の実測の「4個・8個」がこれ。
マルチスレッド・マルチプロセスは、1つのプログラムの中で複数の処理を進めるための作り方の名前で、OS のマルチタスクの上に成り立っています。Python で処理を並列にする方法は、関連記事「Python並列処理|concurrent.futures使い分けと速度比較」で扱っています。
最初の5分:Linuxで処理を同時に動かしてマルチタスクを見る
この節では、特別な道具を入れずに、ターミナルだけで OS のマルチタスクを目で確かめる最小の手順が分かります。
計算を続けるだけのコマンドをコアの数より多く同時に動かすと、それぞれの CPU 使用率がコアの数を分け合った値になります。次の手順は Linux(WSL2 や Mac のターミナルでも ps の項目以外はほぼ同じ)で動きます。8秒で自動的に止まるように timeout を付けています。
コアの数を確かめる
nproc を実行する。この記事の環境では 2 と表示された。
コアより多く同時に動かす
計算だけを続ける sh を4つ、裏で(末尾の &)同時に始める。
CPU 使用率と動いているコアを見る
ps の %CPU と PSR(最後に動いたコアの番号)を見る。
切り替えられた回数を見る
/proc/<PID>/status の nonvoluntary_ctxt_switches を見る。
nproc
for i in 1 2 3 4; do timeout 8 sh -c 'while :; do :; done' & done
sleep 4
ps -o pid,stat,psr,pcpu,etime,args --ppid "$(pgrep -d, -x timeout)"
grep ctxt /proc/25355/status # 上の ps に出た PID を1つ指定する
2
PID STAT PSR %CPU ELAPSED COMMAND
25355 R 0 45.6 00:04 sh -c while :; do :; done
25356 R 0 47.0 00:04 sh -c while :; do :; done
25357 R 1 46.7 00:04 sh -c while :; do :; done
25358 R 1 49.0 00:04 sh -c while :; do :; done
voluntary_ctxt_switches: 0
nonvoluntary_ctxt_switches: 598
[1] Exit 124 timeout 8 sh -c 'while :; do :; done'
4つの処理は、コア0とコア1に2つずつ分かれて、それぞれ約46〜49%の CPU を使っていました。STAT の R は「実行中、または実行できる状態で順番を待っている」という意味です。4秒の間に598回、OS から順番を取り上げられています(nonvoluntary)。自分から順番を譲った回数(voluntary)は0回で、計算しかしていない処理は自分からは止まらないことが分かります。最後の Exit 124 は、timeout が時間切れで止めたという意味で、エラーではありません。
自分で確かめる(ターミナルで1行):bash で grep ctxt /proc/$BASHPID/status を実行すると、今使っているシェル自身が何回切り替えられたかが分かります。この環境で起動したばかりの bash では voluntary が0、nonvoluntary が1で、ls と sleep 0.2 を3回ずつ実行したあとは voluntary が6に増えました。コマンドの終わりや sleep を待つたびに、自分から順番を譲っているためです。
ps と top の各項目の意味は、関連記事「Linux topコマンドの見方 全項目の意味と操作キー早見表」で扱っています。
OSのマルチタスクの仕組み:時分割と約4ミリ秒の持ち時間(実測)
この節では、OS が1つのコアをどのくらいの細かさで切り替えているかと、処理が増えると待ち時間がどう延びるかが、実際の記録で分かります。
OS は、CPU の時間を細かく区切って処理に順番に配ります。これを時分割(タイムシェアリング)と呼び、1回に配る時間をタイムスライス(持ち時間)と呼びます。Microsoft Learn の「Multitasking」では、Windows はスレッドごとにタイムスライスを割り当て、時間が来ると実行中のスレッドを止めて別のスレッドを動かすこと、1回は約20ミリ秒と小さいため複数のスレッドが同時に動いているように見えることが説明されています。長さは OS とプロセッサによって変わる、とも書かれています。
Linux の持ち時間を実際に測るため、時計を読み続けて「50マイクロ秒より長く時計が飛んだ瞬間」を記録するプログラムを作りました。時計が飛んだ間は、OS がほかの処理を動かしていた時間です。飛ぶ直前まで続けて動けた長さが、1回の持ち時間になります。taskset -c 1 で全部をコア1に集め、1個・2個・3個で3秒ずつ動かしました。
/* gap.c:時計が 50us 以上飛んだら「切り替えられた」と数える */
long t = ns();
if (t - last > 50000) { runs[nr] = last - runst; gaps[nr] = t - last; nr++; runst = t; }
last = t;
## taskset -c 1, N=1 load=1.44
pid=2959 sec=3.0 ran=2.37s (79%) switches_out=616 run_median=0.69ms run_p90=11.68ms gap_median=0.12ms gap_p90=2.31ms
## taskset -c 1, N=2 load=1.40
pid=3074 sec=3.0 ran=1.29s (43%) switches_out=410 run_median=3.95ms run_p90=3.98ms gap_median=4.02ms gap_p90=8.04ms
pid=3075 sec=3.0 ran=1.29s (43%) switches_out=384 run_median=3.96ms run_p90=3.98ms gap_median=4.02ms gap_p90=8.07ms
## taskset -c 1, N=3 load=1.61
pid=3111 sec=3.0 ran=0.91s (30%) switches_out=287 run_median=3.97ms run_p90=3.98ms gap_median=8.02ms gap_p90=8.45ms
pid=3112 sec=3.0 ran=0.91s (30%) switches_out=278 run_median=3.97ms run_p90=3.98ms gap_median=8.02ms gap_p90=8.42ms
pid=3113 sec=3.0 ran=0.92s (31%) switches_out=285 run_median=3.97ms run_p90=3.98ms gap_median=8.02ms gap_p90=8.87ms
1つのコアに2個・3個を集めると、どの処理も約4ミリ秒動いては止まり、ほかの処理が動く間待つ、を繰り返していました。2個なら待ちは約4ミリ秒、3個なら約8ミリ秒で、待つ時間は「ほかの処理の数 × 4ミリ秒」になっています。1秒に約95回も入れ替わるため、人の目には3つが同時に動いているように見えます。
1個だけのときは、本来は切り替えが起きないはずですが、616回切り替えられていました。同じマシンでほかの作業が動いていたためで、そのぶん使えた時間も79%に下がっています。また、3個のときの合計が約91%で100%に届かないのも同じ理由です。
このカーネルは、1秒に250回(4ミリ秒ごと)のタイマー割り込みで動く設定(CONFIG_HZ=250)です。測った持ち時間がほぼ4ミリ秒ちょうどだったのは、切り替えの判断がタイマー割り込みのたびに行われるためと考えられます。Linux のスケジューラーは版によって変わっていて、カーネルの公式ドキュメントによると、6.6 から CFS に代わる EEVDF(Earliest Eligible Virtual Deadline First)への移行が始まりました。EEVDF は、同じ優先度の処理に CPU の時間を公平に配ることを目指し、「受け取るべき時間をまだ受け取っていない」処理の中から、仮想的な締め切りがいちばん早いものを選んで動かします。
| OS | 切り替えの方式 | 持ち時間の目安 | 出どころ |
|---|---|---|---|
| Linux 6.18(この記事の環境) | プリエンプティブ。EEVDF で公平に配る | 約4ミリ秒(実測。設定と負荷で変わる) | 手元の実測・カーネルの公式ドキュメント |
| Windows | プリエンプティブ。スレッドにタイムスライスを配る | 約20ミリ秒(OS とプロセッサで変わる) | Microsoft Learn「Multitasking」 |
| Linux の SCHED_RR(リアルタイム用) | 同じ優先度の中で順番に回す | この環境の sched_rr_timeslice_ms(/proc/sys/kernel の下)は 100 |
手元で読んだ値 |
処理には「実行できる(順番待ち)」「何かを待って眠っている」などの状態があり、OS は「実行できる」状態の処理だけに CPU を配ります。キーボードの入力やディスクの読み込みを待っている処理は、待っている間 CPU を使いません。この環境では、92個のプロセス(スレッドにすると135個)が2つのコアを分け合っていましたが、そのとき実行できる状態だったのは2個だけでした。ほとんどの処理は、ほとんどの時間、何かを待って眠っています。
コンテキストスイッチとは:切り替えの回数とコスト(実測)
この節では、処理を切り替えるときに OS が何をしているか、1回の切り替えにどのくらい時間がかかるか、何回くらい切り替えているかが分かります。
コンテキストスイッチは、実行中の処理を止めるときに、その処理の途中の状態(レジスターの値・次に実行する場所など。これをコンテキストと呼ぶ)を保存し、次に動かす処理の状態を戻す作業です。切り替えには2種類あります。
| 種類 | /proc の表示 | 起きる場面 | 手元の実測 |
|---|---|---|---|
| 自分から譲る | voluntary_ctxt_switches | 入力・ファイル・ネットワーク・sleep を待つとき | 1ミリ秒眠るのを1,000回:voluntary 1,004回・involuntary 1回 |
| 取り上げられる | nonvoluntary_ctxt_switches | 持ち時間が切れた、より優先すべき処理が来た | 計算だけを1.39秒:voluntary 4回・involuntary 162回 |
./spin 3000000000 wall=1.39s cpu=1.33s voluntary=4 involuntary=162
./beat 1000 wall=1.22s cpu=0.02s voluntary=1004 involuntary=1
sh -c 'for i in $(seq 200); do cat /etc/ wall=0.27s cpu=0.24s voluntary=591 involuntary=184
1ミリ秒眠っては起きるプログラムは、1.22秒のうち CPU を使ったのは0.02秒だけで、ほとんど眠って待っていました。その間、CPU はほかの処理に使われます。これが、マルチタスクで CPU を無駄なく使える理由です。
次に、1回の切り替えにかかる時間を測りました。2つのプロセスの間でパイプを使って1バイトを20万回往復させ、1往復の時間を求めます。同じコアに2つを置くと、1往復ごとに2回の切り替えが起きます。
cpuA=0 cpuB=0 roundtrips=200000 total=0.609s per_roundtrip=3.05us per_switch(approx)=1.52us
cpuA=0 cpuB=1 roundtrips=200000 total=7.881s per_roundtrip=39.40us per_switch(approx)=19.70us
cpuA=0 cpuB=0 roundtrips=200000 total=0.635s per_roundtrip=3.18us per_switch(approx)=1.59us
cpuA=0 cpuB=1 roundtrips=200000 total=7.444s per_roundtrip=37.22us per_switch(approx)=18.61us
cpuA=0 cpuB=0 roundtrips=200000 total=0.550s per_roundtrip=2.75us per_switch(approx)=1.37us
cpuA=0 cpuB=1 roundtrips=200000 total=9.993s per_roundtrip=49.97us per_switch(approx)=24.98us
同じコアでは、1往復が約2.8〜3.2マイクロ秒、切り替え1回あたり約1.4〜1.6マイクロ秒でした(パイプの読み書きの時間も含んだ目安です)。4ミリ秒の持ち時間に比べると約2,600分の1で、計算の邪魔になるほどではありません。一方、別々のコアに置くと1往復が37〜50マイクロ秒と10倍以上かかりました。眠っている相手のコアを起こす手間がかかるためで、この仮想マシンではその手間が特に大きく出ています。「コアが多いほど何でも速い」とは限らない例です。
マシン全体の切り替え回数は、/proc/stat の ctxt 行か vmstat の cs 列で見られます。この環境では、静かなときで1秒に約1,650回、計算を動かしている間は1秒に約7,900〜9,900回でした。
$ vmstat 1 3
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
0 0 0 5571812 265640 1548632 0 0 2858 168 3425 46 25 5 69 1 0 0
1 0 0 5313832 265640 1552484 0 0 1060 32 2299 9870 50 21 27 1 2 0
0 0 0 5308052 265640 1560592 0 0 0 8 2243 7872 53 17 29 0 2 0
vmstat の1行目は起動してからの平均なので、2行目以降を見ます。
切り替えの手間が小さいことは、処理の数を増やしても全体の時間がほとんど変わらないことでも確かめられます。同じ量の計算(合計120億回)を、2個から128個に分けて同時に動かしました。3回測った結果です。
| 分けた数 | 1回目 | 2回目 | 3回目 |
|---|---|---|---|
| 2個 | 3.15秒 | 2.93秒 | 4.21秒 |
| 8個 | 2.91秒 | 3.37秒 | 4.15秒 |
| 32個 | 2.77秒 | 3.22秒 | 3.29秒 |
| 128個 | 3.72秒 | 4.31秒 | 4.07秒 |
ほかの作業の影響で回ごとに1秒ほどの揺れがありますが、2個から32個までは同じくらいでした。128個では少し延びていて、プロセスを128個起動する手間も含まれています。計算だけの処理なら、OS の切り替えの手間はごくわずかです。ただし、たくさんのデータを扱う処理では、切り替えのたびに CPU のキャッシュ(手元に置いた最近のデータ)が入れ替わるため、ここでの測定より大きな損が出ることがあります。キャッシュの働きは、関連記事「CPUの気持ち8選|分岐予測・キャッシュライン・高速化」で扱っています。
プリエンプティブと協調的マルチタスクの違い(実測)
この節では、マルチタスクの2つの方式の違いと、1つの処理が順番を譲らないと何が起きるかが、Python と Node.js の実行結果で分かります。
プリエンプティブ・マルチタスクは、OS が持ち時間の切れた処理から強制的に CPU を取り上げる方式です。協調的(ノンプリエンプティブ)マルチタスクは、それぞれの処理が自分から順番を譲るまで、ほかの処理は動けない方式です。今の Windows・macOS・Linux はプリエンプティブで、前の節の nonvoluntary(取り上げられた)切り替えがその証拠です。協調的な方式は、1つでも譲らない処理があると全体が止まります。
協調的な方式は今もプログラムの中で使われています。Python の asyncio や JavaScript のイベントループは、1つのスレッドの中で await のところで順番を譲り合う、協調的マルチタスクです。100ミリ秒ごとに時刻を記録する「鼓動」の処理と、1秒間計算を続ける処理を一緒に動かし、鼓動の間隔がいちばん空いたときの長さを測りました。
async def worker_no_yield():
busy(1.0) # await しないで1秒計算する
async def worker_yield():
for _ in range(100): # 10ms ごとに順番を譲る
busy(0.01)
await asyncio.sleep(0)
協調(asyncio・譲らない) 鼓動の最大間隔 1051 ms
協調(asyncio・10msごとに譲る)鼓動の最大間隔 132 ms
スレッド(OSが切り替える) 鼓動の最大間隔 134 ms
sys.getswitchinterval() = 0.005
協調(asyncio・譲らない) 鼓動の最大間隔 1050 ms
協調(asyncio・10msごとに譲る)鼓動の最大間隔 120 ms
スレッド(OSが切り替える) 鼓動の最大間隔 105 ms
計算の途中で一度も譲らないと、100ミリ秒ごとのはずの鼓動が約1,050ミリ秒止まりました。10ミリ秒ごとに await asyncio.sleep(0) で譲ると、遅れは20〜30ミリ秒ほどに収まりました。スレッドで動かした場合は、Python が5ミリ秒(sys.getswitchinterval() の値)ごとに実行権を切り替えるため、譲る処理を書かなくても止まりませんでした。
Node.js でも同じことが起きます。100ミリ秒ごとの setInterval を動かしている途中で、1秒間計算を続けました。
const timer = setInterval(() => { /* 前回からの間隔を記録 */ }, 100);
setTimeout(() => { // 300ms 後に、1秒間ずっと計算する
const end = performance.now() + 1000;
while (performance.now() < end) {}
}, 300);
setInterval(100ms) の最大間隔: 1100 ms
ブラウザーで重い計算をすると画面が固まるのはこのためです。イベントループの順番の決まりは、関連記事「JavaScriptイベントループ|マイクロタスクの実行順を図とクイズで」で扱っています。
async 関数の中で重い計算をするとき
await を挟まずに長い計算や time.sleep() を書くawait asyncio.sleep()譲らない間は、ほかの処理がすべて止まる(実測で約1秒)
処理を速くしたいとき
2コアで4個にすると、1個あたりの時間は約2倍になった
パソコンの OS も、昔は協調的マルチタスクが使われていました。NTT 東日本の用語解説でも、ノンプリエンプティブ方式ではアプリケーション側の都合で CPU の使用時間が決まり、プリエンプティブ方式では OS が CPU の使用時間と順番を管理する、と説明されています。協調的な方式では、1つのアプリが固まると OS ごと操作できなくなることがありました。
優先度で配分が変わる:nice値とCPUの分け方(実測)
この節では、OS が「どの処理にどれだけ CPU を配るか」を優先度で調整する仕組みと、その効き方が実際の数値で分かります。
マルチタスクの OS は、すべての処理に同じだけ配るとは限りません。Linux では nice 値(-20〜19。大きいほど控えめ)で配分を変えられます。man ページの sched(7) によると、nice 値が1違うごとに、優先される側への配分が1.25倍になります。1つのコアに nice 0 の処理と、nice を変えた処理を一緒に置き、4秒間にそれぞれが使えた時間を測りました。
taskset -c 0 ./gap 4 &
taskset -c 0 nice -n 10 ./gap 4 &
wait
| 組み合わせ | nice 0 が使えた時間 | 相手が使えた時間 | 実測の比率 | 1.25倍の規則から求めた比率 |
|---|---|---|---|---|
| nice 0 と nice 0 | 1.59秒 | 1.59秒 | 50:50 | 50:50 |
| nice 0 と nice 5 | 1.51秒 | 0.50秒 | 75:25 | 75.3:24.7 |
| nice 0 と nice 10 | 3.47秒 | 0.39秒 | 90:10 | 90.3:9.7 |
| nice 0 と nice 19 | 3.67秒 | 0.09秒 | 97.6:2.4 | 98.6:1.4 |
比率は、規則から求めた値とほぼ一致しました(合計が4秒に届かないのは、ほかの作業にも時間が配られたためです)。nice 19 の処理は、4秒のうち0.09秒しか動けず、次の順番まで約275ミリ秒(中央値)待っていました。夜間のバックアップや大きなファイルの圧縮を nice -n 19 で動かすと、ふだんの作業の邪魔になりにくいのはこのためです。
動かしている処理の nice 値は、ps -o pid,ni,comm の NI 列や top の NI 列で見られます。一般ユーザーが nice 値を下げる(優先する)ことはできず、試すと次のように断られます。
$ nice -n -5 true # 一般ユーザーで実行
nice: cannot set niceness: Permission denied
$ chrt -f 50 true # リアルタイムの優先度も同じ
chrt: failed to set pid 0's policy: Operation not permitted
GNU の nice は、優先度の変更に失敗してもコマンド自体は実行し、終了コードは0でした。メッセージを見落とすと、優先度が変わったつもりになるので注意が要ります。Windows で CPU を使っている処理を見るタスク マネージャーの開き方と画面は、関連記事「タスクマネージャーの開き方|ショートカット7つと使い方・開かない時の対処」で扱っています。
たくさん同時に動かすと何が起きるか(応答の遅れの実測)
この節では、処理の数がコアより多くなったとき、パソコンが「重い」と感じる理由が、待ち時間の遅れの数値で分かります。
OS は計算の多い処理より、待ちから起きた処理を早めに動かすので、ふだんの応答はあまり遅れません。ただし、処理の数が増えると、ときどき大きな遅れが出るようになります。1ミリ秒眠って起きる、を2,000回繰り返すプログラムで、「予定より何ミリ秒遅れて起きたか」を測りました。裏で計算だけの処理を0個・2個・8個・32個動かしています。
bg=0 load=10.93 wakeups=2000 late_median=0.090ms late_p99=0.453ms late_max=3.219ms
bg=2 load=10.22 wakeups=2000 late_median=0.071ms late_p99=2.242ms late_max=30.184ms
bg=8 load=10.22 wakeups=2000 late_median=0.071ms late_p99=3.797ms late_max=18.331ms
bg=32 load=10.12 wakeups=2000 late_median=0.079ms late_p99=9.607ms late_max=235.578ms
| 裏で動かした計算 | 遅れの中央値 | 遅いほうから1% | いちばん遅れたとき |
|---|---|---|---|
| 0個 | 0.09ミリ秒 | 0.45ミリ秒 | 3.2ミリ秒 |
| 2個 | 0.07ミリ秒 | 2.2ミリ秒 | 30ミリ秒 |
| 8個 | 0.07ミリ秒 | 3.8ミリ秒 | 18ミリ秒 |
| 32個 | 0.08ミリ秒 | 9.6ミリ秒 | 236ミリ秒 |
裏で32個の計算を動かしても、遅れの中央値は0.1ミリ秒以下のままでした。眠っていた処理は「受け取るべき時間をまだ受け取っていない」側になるため、起きたときに早めに順番が回ってくるからです。ところが、遅いほうから1%の遅れは0.45ミリ秒から9.6ミリ秒へ、いちばん大きな遅れは236ミリ秒まで延びました。画面の動きやキー入力でいえば、ときどき引っかかる「カクつき」に当たります。この測定は同じマシンのほかの作業で load average が10前後あるときに行ったため、裏の計算が0個でも最大3ミリ秒の遅れが出ています。
実行待ちの数の平均は load average(ロードアベレージ)で見られ、uptime や cat /proc/loadavg で確かめられます。コアの数を大きく超える状態が続くと、待ちが積み上がって応答が悪くなります。Linux で重い処理を見つけて止める方法は、関連記事「Linuxプロセス確認と停止|ps・top・kill逆引きコマンド一覧」で扱っています。
- 1コアの数を知るnproc、タスク マネージャーの「論理プロセッサ」
- 2実行待ちの数を見るload average がコアの数を大きく超えていないか
- 3CPU を使っている処理を特定するtop・タスク マネージャー・アクティビティモニタで上から見る
- 4止めるか、控えめにする不要なら終了、必要なら nice や優先度で後回しにする
自分のパソコンでマルチタスクを確かめる(Windows・Mac・Linux・ブラウザー)
この節では、自分のパソコンのコアの数と、いまどれだけの処理が CPU を分け合っているかを、OS ごとに確かめる場所が分かります。
まずコアの数(同時に計算できる数)を知り、次に CPU を使っている処理の一覧を見ます。コアの数より多くのアプリが動いていても、多くは待っているだけなので問題ありません。CPU を使い続けている処理が、コアの数より多いときに重くなります。
Windows
スタートボタンを右クリック →「タスク マネージャー」(Ctrl+Shift+Esc でも開く)→ 左の「パフォーマンス」→「CPU」。
「コア」と「論理プロセッサ」の数値を見る
Mac
アクティビティモニタを開き、ツールバーの「CPU」をクリック。「ウインドウ」→「CPU使用率」で現在の状況も見られる。
下部の「システム」「ユーザ」「アイドル状態」を見る
Linux
nproc でコアの数、top で CPU を使っている順、uptime で実行待ちの平均。
この環境では nproc が 2
ブラウザー
開発者ツール(F12)のコンソールで navigator.hardwareConcurrency と打つ。
論理プロセッサの数が返る
自分で確かめる(ブラウザーの開発者ツールで1行):コンソールに navigator.hardwareConcurrency と入力すると、ブラウザーが使える論理プロセッサの数が返ります。この記事の環境で Chromium 153 のヘッドレス版にこの値を表示するページを読ませたところ、hardwareConcurrency=2 と出て、nproc の値と一致しました。MDN によると、ブラウザーは同時に動かせる Worker の数に合わせて、実際より少ない数を返すことがあるため、コアの数の正確な値としては扱わないよう注意されています。
自分で確かめる(Windows の設定画面):Microsoft サポートの「Windows デバイスのプロセッサに搭載されているコアの数を確認する」の手順どおり、タスク マネージャーの「パフォーマンス」→「CPU」で「コア」と「論理プロセッサ」の数値を見ます。論理プロセッサの数がコアの数の2倍なら、1つのコアで2つの処理を同時に進める仕組み(Intel のハイパースレッディングなど)が働いています。
$ lscpu | grep -E '^CPU\(s\)|Thread|Core|Socket|Model name'
CPU(s): 2
Model name: Intel(R) Xeon(R) Processor @ 2.10GHz
Thread(s) per core: 1
Core(s) per socket: 2
Socket(s): 1
人のマルチタスク:シングルタスクとの違い・メリットとデメリット
この節では、仕事の進め方としてのマルチタスクについて、心理学の研究で分かっていることと、OS の仕組みから借りられる考え方が分かります。
人のマルチタスクも、実際には注意を素早く切り替えているだけで、切り替えるたびに時間を失います。米国心理学会(APA)の「Multitasking: Switching costs」は、複数の作業を同時に、または頻繁に切り替えながら行うと、特に複雑な作業で生産性が落ち、ミスも増えるという研究(Rubinstein・Meyer・Evans、2001年など)を紹介しています。同じ記事では、研究者の Meyer 氏が、切り替えのコストは小さくても積み重なり、生産的な時間の最大40%を失うこともある、と述べています。この40%は、実験で測った値ではなく研究者の見積もりとして紹介されている数字です。
ここに OS との違いがあります。コンピューターの切り替えは1回約1.5マイクロ秒で、持ち時間4ミリ秒のごく一部でした。人の場合は、どこまで進めたか・次に何をするかを思い出す「頭の中のコンテキストスイッチ」が重く、切り替えの手間が作業の時間に対して大きくなりがちです。
| 観点 | マルチタスク(人) | シングルタスク(人) |
|---|---|---|
| 進め方 | 複数の仕事を並べて、細かく切り替えながら進める | 1つの仕事に区切りがつくまで集中して進める |
| よい点 | 複数の仕事を止めずに進められる、全体の状況をつかみやすい、問い合わせにすぐ応じられる | 切り替えの損がない、ミスが減る、深く考える仕事が進む |
| 気をつける点 | 抱えすぎて手が回らなくなる、切り替えで時間を失う、焦りやすい、生産性が下がる | 急ぎの連絡への反応が遅れる、ほかの人の仕事を待たせることがある |
| 向く仕事 | 短く単純な作業が多い、複数の人の進み具合を見る仕事(管理職・医療従事者など) | 設計・文章・分析・プログラミングなど、考える時間が長い仕事 |
マルチタスクが苦手な人の特徴として、品質へのこだわりが強い・完璧主義の傾向がある、が挙げられることもあります。1つの仕事を仕上げてから次に移りたい人ほど、途中で切り替えられると負担が大きいためです。苦手を克服するコツとして紹介されることの多い方法は、OS のマルチタスクの考え方にそのまま置き換えられます。
| 人の作業のコツ | 中身 | OS で対応する考え方 |
|---|---|---|
| 時間を区切って1つずつ | 25分・1時間など、決めた時間は1つの仕事だけをする | タイムスライス。ただし人は持ち時間を長めにとる |
| 「1×10×1」で片付ける | 1分・10分・1時間で終わる仕事の順に片付ける | 短い処理を先に済ませて、待っている数を減らす |
| パーキングロット(割り込みはメモ) | 途中で思いついたこと・頼まれたことはメモして後で対応する | 割り込みは受け付けるが、今の処理が区切りまで進んでから動かす |
| 優先順位をつける | 急ぎ・大事な仕事から手を付け、締め切りを確かめる | nice 値・優先度、締め切りの早いものから選ぶ EEVDF |
| 集中できる環境を整える | 通知を切る、メールを見る時間を決める | 不要な割り込みを減らし、切り替えの回数自体を減らす |
| タスク管理ツールで見える化 | 抱えている仕事と状態(待ち・進行中)を一覧にする | ps・top で「実行中」「待ち」を一覧にする |
OS も人も、「待っている間に別のことを進める」マルチタスクは効率を上げます。たとえば、ビルドやテストの完了を待つ間に、レビューのコメントを読むような使い方です。一方、「考える作業どうしを細かく行き来する」マルチタスクは、切り替えの手間で効率を下げます。この区別が、マルチタスクとうまく付き合う鍵です。
よくあるエラーとつまずき(原文つき)
この節では、この記事の検証で実際に出たメッセージと、マルチタスクを扱うときにつまずきやすい点の意味と直し方が分かります。
| 出たメッセージ・様子 | 場面 | 意味と直し方 |
|---|---|---|
taskset: failed to set pid 22832's affinity: Invalid argument |
2コアのマシンで taskset -c 2 を実行 |
コアの番号は0から数える。2コアなら0と1だけ。nproc で数を確かめる |
nice: cannot set niceness: Permission denied |
一般ユーザーで nice -n -5 |
優先度を上げるには管理者の権限が要る。コマンドは実行されるので見落としに注意 |
chrt: failed to set pid 0's policy: Operation not permitted |
一般ユーザーでリアルタイムの優先度を指定 | リアルタイムの優先度は管理者だけが設定できる。ほかの処理を止めてしまうため、ふだんは使わない |
RuntimeWarning: coroutine 'job' was never awaited |
Python で async 関数を await なしで呼んだ |
呼んだだけでは動かない。await job() にするか asyncio.create_task(job()) で予約する |
RuntimeError: asyncio.run() cannot be called from a running event loop |
async 関数の中で asyncio.run() を呼んだ |
イベントループは1つのスレッドに1つ。中では await を使う |
| 鼓動・タイマーが約1秒止まる | asyncio・Node.js で重い計算を続けた | 協調的な方式では譲らない処理が全体を止める。分割して譲るか、別スレッド・別プロセスへ |
undefined reference to `CPU_ZERO' |
C で sched_setaffinity を使った |
ファイルの先頭に #define _GNU_SOURCE を書いてから sched.h を読み込む |
Exit 124 |
timeout 8 を付けたコマンドの終了 |
timeout が時間切れで止めたという意味。エラーではない |
- 1CPU 使用率は「何コア分か」を確かめて読むtop のプロセスごとの %CPU は1コアを100%とする。2コアなら最大200%になりうる
- 2処理の数とコアの数を比べる計算だけの処理はコアの数まで。超えると1個あたりが遅くなる
- 3async の中で止める書き方をしていないかtime.sleep・重いループ・同期のファイル読み込み
- 4測るときはほかの処理の影響を書き残すload average を一緒に記録し、何回か測る
判断表:マルチタスク・並列処理・シングルタスクをどう選ぶか
この節では、プログラムを作るときと、人が仕事を進めるときに、どの進め方を選べばよいかの目安が分かります。
基本は「待ちが多い作業は並行に、計算が多い作業はコアの数まで並列に、考える作業は1つずつ」です。
| 作業の性質 | プログラムでの選び方 | 人の作業での選び方 | 根拠(この記事の実測) |
|---|---|---|---|
| 待ちが多い(通信・ファイル・返事待ち) | asyncio・イベントループ・スレッドで並行に進める | 待つ間に別の短い仕事を進める | 1ms 眠る処理は1.22秒中 CPU 0.02秒 |
| 計算が多い(変換・集計・圧縮) | コアの数までプロセスで並列にする | まとまった時間を取り、1つずつ片付ける | 2コアで2個は1.6秒、4個は3.0秒 |
| 急ぎではない重い処理 | nice 19 などで控えめに動かす | 手が空く時間帯にまとめて行う | nice 19 は nice 0 の約40分の1 |
| 応答の速さが大事(画面・操作) | 重い計算を別スレッド・Web Worker に逃がす | 問い合わせを受ける時間を決めて、すぐ返す | 譲らない計算で応答が約1秒止まった |
| 深く考える(設計・文章・分析) | (該当なし) | 通知を切り、シングルタスクで進める | APA が紹介する切り替えのコスト |
よくある質問
この節では、マルチタスクについてよく聞かれる疑問への短い答えが分かります。
Q. マルチタスクとは簡単に言うと何ですか? A. 複数の作業を同時に進めることです。コンピューターでは、OS が CPU を数ミリ秒ずつ順番に別の処理へ切り替えて、たくさんのアプリが同時に動いているように見せる仕組みを指します。
Q. コアが1つの CPU でもマルチタスクはできますか? A. できます。マルチタスクはもともと1つの CPU を切り替えて使う仕組みです。この記事でも、1つのコアに3個の計算を置くと、それぞれが約4ミリ秒ずつ交代で動き、使用率は約30%ずつになりました。
Q. マルチタスクとマルチスレッドの違いは? A. マルチタスクは OS が複数の処理を同時に動かす仕組み全体を指し、マルチスレッドは1つのプログラムの中で複数の流れ(スレッド)を動かす作り方です。スレッドは OS のマルチタスクによって切り替えられます。
Q. マルチタスクとマルチプロセスの違いは? A. マルチプロセスは、1つの仕事を複数のプロセス(メモリを別々に持つ実行中のプログラム)に分ける作り方です。マルチタスクの OS があるからこそ、複数のプロセスを同時に動かせます。
Q. スマホもマルチタスクですか? A. iOS も Android もマルチタスクの OS です。ただし、電池を長持ちさせるため、画面に出ていないアプリの動きは OS が制限することがあります。アプリを切り替える画面や、2つのアプリを並べる機能を「マルチタスク」と呼ぶこともあります。
Q. アプリをたくさん開くとパソコンが重くなるのはなぜ? A. 多くのアプリは待っているだけで CPU をほとんど使いません。重くなるのは、CPU を使い続ける処理がコアの数より多いときか、メモリが足りなくなったときです。この記事の実測では、裏で32個の計算を動かすと、ときどき236ミリ秒の遅れが出ました。
Q. 切り替えにかかる時間(コンテキストスイッチ)はどのくらいですか? A. 環境によりますが、この記事の環境では同じコアの中で1回あたり約1.4〜1.6マイクロ秒でした。別のコアとのやり取りは10倍以上かかりました。
Q. Linux のカーネルの設定が「Dynamic Preempt: none」でもプリエンプティブですか?
A. ふつうのアプリ(ユーザー空間)の処理は、持ち時間が切れれば取り上げられます。この記事の環境も起動時の表示は Dynamic Preempt: none でしたが、計算だけの処理は1秒に約95回取り上げられていました。none が指すのは、カーネル自身の処理の途中で切り替えるかどうかの設定です。
Q. 人はマルチタスクが得意になれますか? A. 単純で慣れた作業どうしなら、同時にこなしやすくなります。一方、複雑な作業どうしの切り替えにはコストがかかるという研究が多く、米国心理学会も切り替えによって時間を失うと紹介しています。得意を目指すより、待ち時間を活かす・考える作業は1つずつ、と使い分けるほうが確実です。
Q. マルチタスクの反対は何ですか? A. シングルタスクです。人の作業では1つに集中して進めること、コンピューターでは一度に1つのプログラムしか動かせない仕組み(初期のパソコンの OS など)を指します。
まとめ
- マルチタスクとは、複数の作業を同時に進めること。OS では、CPU を数ミリ秒ずつ切り替えて、複数の処理が同時に動いているように見せる仕組みを指す。
- マルチコアは計算する部品が複数あること。2コアで計算を2個動かすと1.6秒で並列に終わり、4個では3.0秒、8個では5.8秒と、コアを分け合うぶん延びた。
- 手元の Linux 6.18 は、1つのコアの処理を約4ミリ秒ずつ交代させていた。切り替え1回は約1.5マイクロ秒で、計算だけなら数を増やしても全体の時間はほぼ変わらない。
- 今の OS はプリエンプティブ。asyncio や JavaScript のような協調的な方式では、譲らない計算が1つあるだけで全体が約1秒止まった。nice 値の配分は1.25倍の規則どおりだった。
- 人のマルチタスクは切り替えの手間が大きい。待ち時間には別の仕事を進め、考える作業は時間を区切って1つずつ進める。
参考・出典
確認日はいずれも 2026年10月29日です。
- Microsoft Learn「Multitasking」(Win32 apps):https://learn.microsoft.com/en-us/windows/win32/procthread/multitasking
- Microsoft サポート「Windows デバイスのプロセッサに搭載されているコアの数を確認する」:https://support.microsoft.com/ja-jp/article/3126ef99-0247-33b3-81fc-065e9fb0c35b
- Apple サポート「MacのアクティビティモニタでCPUの動作状況を表示する」:https://support.apple.com/ja-jp/guide/activity-monitor/actmntr43452/mac
- The Linux Kernel documentation「EEVDF Scheduler」:https://docs.kernel.org/scheduler/sched-eevdf.html
- The Linux Kernel documentation「CFS Scheduler」:https://docs.kernel.org/scheduler/sched-design-CFS.html
- Linux man-pages「sched(7)」:https://man7.org/linux/man-pages/man7/sched.7.html
- American Psychological Association「Multitasking: Switching costs」:https://www.apa.org/topics/research/multitasking
- NTT東日本 BizDrive「マルチタスク」:https://business.ntt-east.co.jp/content/bizdrive/word/multi-task.html
- Python ドキュメント「asyncio」「sys.getswitchinterval」:https://docs.python.org/ja/3/library/asyncio.html
- MDN「Navigator: hardwareConcurrency プロパティ」:https://developer.mozilla.org/ja/docs/Web/API/Navigator/hardwareConcurrency
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「マルチタスクとは|OSの4ミリ秒の切り替えを実測・人の作業との違い」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。