JavaScriptのコールスタックやイベントループについて調べていくと、必然的に「スレッド」について理解をしたくなってきました。
そこで、今回は「Fetchを資料下非同期Webプログラミング」の番外編として、「スレッド」について、まとめました。
Wikipediaの英語版がたいへんに参考になりました。
Wikipediaにわかりやすくまとまっている図があったので、ここに掲載しておきます。
この図を以下の説明と照らし合わせると理解が進むと思います。


プログラムソースコードはコンパイルなどによりマシン語に翻訳されます。
マシン語は、2進数で表現されたCPUが直接理解して実行できる言語です。
プログラムを実行するときは、マシン語がメモリ上にローディングされ、コードとデータがメモリ上に割り当てられます。
メモリ上に割り当てられたプログラムやデータのことをプロセスと言います。
プロセスは、プログラムコード、割り当てられたシステムリソース、アクセス権限などで構成されています。
プロセス内においてメモリ空間は共有されますが、他のプロセスのメモリ空間とは完全に独立しています。
メモリに割り当てられた命令コードは、遂次CPUに送られ(Fetch)、解読され(Decode)、実行(Execute)されます。データなどはCPUのレジストリに保持されます。
このようなプロセスの実行を制御しているのがOS(カーネル)のスケジューラです。
スケジューラは、プロセスの実行をスレッドという単位にして、実行の制御をします。
つまり、プログラムの実行はスレッドという単位で実行されます。
1つのプロセスには1つ以上のスレッドが存在します。
1つのプロセスに1つのスレッドが存在することもあれば、1つのプロセスに複数のスレッドが存在することもあります。
JavaScriptはシングルスレッドの言語なので、1つのプロセスについて1つのスレッドで実行します。
Javaは、言語としてプロセス内に新しいスレッドを作成することができるので、複数のスレッドで実行するようなコーディングができます。
JavaVMのガベージコレクションは、プロセス内で別スレッドとして動作するため、プログラミングではシングルスレッドで記述しても、1つのプロセスで複数スレッドが実行されることがあります。
スケジューラは、あるアルゴリズムによって、スレッドの切り替えを行います。
このスレッドの切り替えをコンテキストスイッチと言います。
スレッドはコンテキストスイッチによって時分割に切り替えが行われます。
スケジュラーによるコンテキストスイッチは、次のルールに基づくアルゴリズムロジックによって、スレッドの切り替えをおこないます。
- スループットの最大化:単位時間あたりに完了する作業量の最大化
- 待機時間の最小化:作業の準備が完了してから実行が開始されるまでの時間の最小化
- レイテンシまたは応答時間の最小化:バッチ処理の場合は準備が完了してから完了するまでの時間、対話型処理の場合はシステムが応答して最初の出力をユーザーに渡すまでの時間の最小化
- 公平性の最大化:各プロセスに均等なCPU時間を割り当てる、または各プロセスの優先度と作業負荷に応じて適切な時間を割り当てる。
複数のプロセス、スレッドが実行しているとき、各スレッドはスケジューラによって、動的に制御されます。
スレッドとは、OSのスケジューラによって管理できる命令コードの最小のシーケンスで、CPUはスケジューラによって割り当てられたスレッドを実行します。
これが、よく言われるスレッドの定義「コンピュータプログラムにおいて特定の処理を行うための一貫性のある命令の流れの事であり、プロセッサ利用の最小単位」の内容です。
OSにスケジューラ、プロセス、スレッドなどの機能が取り入れられた背景には、コンピュータにマルチタスキングやマルチプログラミングの概念が登場したことにあります。
コンピュータが初期の段階では、一度に1つのプログラムしか実行できませんでした。
1つのプログラムがメモリ全体を占有し、他のプログラムと分離されていませんでした。
何せ初期のコンピュータのメモリはわずか64KBしかなく、如何に小さなプログラムコードを書くかということに腐心していました。
それが、時代とともにスケジューラ、プロセス、スレッドの概念が生まれ、OSに組み込まれていきました。
- スケジューラの実現
スケジューラの概念は、1960年代に登場しました。特に、タイムシェアリングシステムの開発が進む中で、複数のユーザーが同時にコンピュータを利用できるようにするために、CPUのスケジューリング技術が確立されました。UNIXの初期バージョン(1970年代)では、ラウンドロビン方式や優先度ベースのスケジューリングが採用されました。 - プロセスの実現
プロセスの概念は、1960年代後半から1970年代にかけて確立されました。特に、MULTICS(1960年代後半)やUNIX(1970年代初頭)の登場により、プロセス管理の仕組みが導入されました。これにより、異なるプログラムが独立したメモリ空間を持ち、並行して実行できるようになりました。 - スレッドの実現
スレッドの概念は、1980年代に登場しました。初期のOSでは、プロセス単位での並行処理が主流でしたが、より軽量な並行処理を実現するためにスレッドが導入されました。特に、Windows NT(1993年)やPOSIXスレッド(1995年)の登場により、スレッドの標準的な管理が確立されました。
時代背景の観点から、スレッドを見直してみると、より理解が深まります。
まだまだ、興味深いことがたくさんあるのですが、ここまでとしておきましょう。