結論
まず結論から言うと「並行・並列」処理と「マルチプロセス・マルチスレッド」は直接関係はありません。
マルチスレッドとマルチプロセス、どちらの方法でも並行にも並列にも処理することができます。「並行・並列」と「プロセス・スレッド」の話はよく同じ文脈に出てくるので混乱しがちですがそれぞれ独立した単語です。「並行・並列」は実行状態を表現するための用語であり、「プロセス・スレッド」はOS側での実行単位の管理の仕方になります。そのため、マルチスレッドなら並行処理のような関係はないということになります。
それでは以下で詳しく説明していきたいと思います。
用語整理
並行と並列
まずは並行と並列について整理していきたいと思います。
こちらはタイムスライスについて学んだことがある方でしたら図を見る図を見るだけで理解できるかなと思います。
並行処理(concurrent)
システムが複数の動作(処理の流れ)を同時に実行状態(in progress)に保てる状態のことを言います。つまり、タイムスライスを利用して一つのプロセッサが複数の処理をしている状態です(このとき、Sleep状態の処理もin progressであるということになります)。図の例で言うとT1とT2が並行な関係になります
並列処理(parallel)
複数の動作を同時に実行できる状態のことを言います。つまり、同じ時間に複数のプロセッサで複数の仕事が行われている状態です。図の例で言うとT1とT3は並列な関係になります。
ここで注意しなくてはならないのが並列は並行を包含しているということです。どういうことかというと、同時に実行している時も「二つの処理は実行状態になっている」という点で並行だと言うことができるのです。
プロセスとスレッド
次にプロセスとスレッドの関係について整理していきます。
プロセス
・「プロセスは実行中のプログラムを抽象化したものである」
・プロセスは実行されるバイナリ
・仮想メモリは、プロセスに対して関連づいている
以上のことからプロセスは実態を伴った処理ではなく、メモリ上で複数または単独の処理をまとめて管理しているものだと考えることができます。(プロセスの最大の目的はプログラムごとのメモリ領域の独立性、不可侵性を保つことです)
スレッド
・「プロセスの中の実行単位」
・スレッドはOSのプロセススケジューラがスケジューリングできる最小の実行単位
・仮想プロセッサは各スレッドに関連づいている
以上のことからスレッドは処理を行う単位だと言うことがわかります。また、スレッドはプロセスの配下にあることもわかります。
また、個人的にはスレッドが一番腹落ちしていなかったのですが、スレッドを理解しにくくしている要素の一つに二つの領域で違う意味で使われている点にあると思います。スレッドと言う単語が使われる場面として「ハードウェア」スレッドと「ソフトウェア」スレッドが存在します。「ハードウェア」スレッドとはCPUのNコア/Nスレッドと言われるスレッドのことで、ソフトウェア側から認識できるプロセッサ数を表す単位になります。「ソフトウェア」スレッドはCPU機能ではなく、オペレーティング環境においてプロセスの中で生成される実行単位になります。ただ、処理を実行する単位という意味は同じなので同じ言葉が利用されているようです。(「ハードウェア」スレッドでは正確にはプロセッサを共有している部分があるのでパフォーマンス面で複数個分だと言い切れないのですがそのあたりの話は省略したいと思います。)
並行・並列とマルチスレッド・マルチプロセスの関係
用語についての説明が終わりましたので次は「並行・並列」「プロセス・スレッド」に関して総当たり式に考えていきます。
まず、前提として「並行、並列」について考えるには処理が二つ以上ないといけませんので考えられるパターンは3つになります。それは「マルチプロセス・シングルスレッド」、「シングルプロセス・マルチスレッド」、「マルチプロセス・マルチスレッド」です。
ポイントは視点をどの高さに持ってくるかで「並行・並列」どちらであるかが変わるというところになります。
マルチプロセス・シングルスレッドと並行・並列
この場合、各プロセスにはスレッドが一つしかありません。そのため、システム全体としては並列に動くことができますが、特定のプログラムではプロセッサを一つしか利用できず並列に動くことができません。
シングルプロセス・マルチスレッドと並行・並列
この場合、システム全体としては一つのプログラムしか動いていませんが、そのプログラムは複数のプロセッサを使って並列に処理を進めることができます。
マルチプロセス・マルチスレッドと並行・並列
この場合、システム全体としても、特定のプログラムとしても並列に処理を進めることができます。
+α
マルチスレッドプロセスがシングルプロセッサ上で動作する場合は、プロセッサが実行リソースを各スレッドに順次切り替えて割り当てるため、プロセスの実行状態は並行的になります。
同じマルチスレッドプロセスが共有メモリー方式のマルチプロセッサ上で動作する場合は、プロセス中の各スレッドが別のプロセッサ上で同時に走行するため、プロセスの実行状態は並列的になります。
プロセスのスレッド数がプロセッサ数と等しいか、それ以下であれば、スレッドをサポートするシステム (スレッドライブラリ) とオペレーティング環境は、各スレッドがそれぞれ別のプロセッサ上で実行されることを保証します。
以上からわかることは「並行・並列」に処理できるかという軸に加えて、「並行・並列」に処理するかという軸があるということです。これについて、「並行・並列」に処理できるかは以上の話の通りで、「並行・並列」に処理するかは"可能な限り並列に処理する"というのが結論になりそうです。
マルチプロセスとマルチスレッドどちらが良いのか
ここで、マルチプロセスとマルチスレッドのどちらでも並列処理できるのであれば、どちらを採用するのが正しいのかという話になると思います。
新しいプロセスを生成するのに比べると、スレッドを生成するのはシステムへの負荷ははるかに小さくなります。これは、新たに生成されるスレッドが現在のプロセスのアドレス空間を使用するからです。スレッドの切り替えに要する時間は、プロセスの切り替えに要する時間よりもかなり短いです。その理由の 1 つは、スレッドを切り替える上でアドレス空間を切り替える必要がないことです。
同じプロセスに属するスレッド間の通信は簡単に実現できます。それらのスレッドは、アドレス空間を含めあらゆるものを共有しているからです。したがって、あるスレッドで生成されたデータを、他のすべてのスレッドがただちに利用できます。
つまり、マルチプロセスにするとメモリ領域が独立しているため安全だが、実行の切り替えにコストがかかると言えそうです。逆にマルチスレッドでは切り替えコストの代わりにスレッドセーフであるかをエンジニアが意識する必要があると言えます。
そしてこの部分を規定しているのは言語仕様なので、採用や習得容易性、更新頻度なども含め技術選択のための項目の一つになるというのが結論となります。
参考文献
https://docs.oracle.com/cd/E19455-01/806-7118/6jg0vp9se/index.html
https://milestone-of-se.nesuke.com/sv-basic/architecture/cpu/
https://yakst.com/ja/posts/39
https://www.oreilly.co.jp/books/9784873114354/
https://www.amazon.co.jp/%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3%E6%8A%80%E8%A1%93%E5%85%A5%E9%96%80-%E9%AB%98%E9%80%9F%E5%8C%96%E3%81%AE%E8%BF%BD%E6%B1%82%C3%97%E6%B6%88%E8%B2%BB%E9%9B%BB%E5%8A%9B%E3%81%AE%E5%A3%81-WEB-PRESS-plus/dp/4774164267/ref=asc_df_4774164267/?tag=jpgo-22&linkCode=df0&hvadid=295723231663&hvpos=&hvnetw=g&hvrand=158268926787210135&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1028853&hvtargid=pla-527289512308&psc=1&th=1&psc=1