コンピュータサイエンス

並行処理と並列処理の違い、シングルコアでも並行処理が可能な理由

並行処理は複数のタスクを切り替えて扱う構造の問題であり、並列処理は同じ瞬間に実行するハードウェアの問題です。シングルコアでも並行処理が成立する理由と、Swift Concurrencyという名前の意味をまとめました。

読了 5 分
並行処理と並列処理の違い、シングルコアでも並行処理が可能な理由のカバー画像

並行処理(concurrency)と並列処理(parallelism)は、韓国語でも英語でも見た目が似ているため、混同して使われがちです。

CPUが1コアしかなかった時代でも、コンピューターは音楽を再生しながら文書を編集できました。物理的には一度に1つしか処理できない機械が、どうして複数のことを「同時に」できたのでしょうか。

この問いに答えられるなら、2つの概念はもう区別できています。答えられないなら、この記事がまさにその点を整理します。

Swift ConcurrencyやGCD(Grand Central Dispatch)のconcurrent queueといった名前も同じです。正しく理解するには、この区別が土台になります。

要点をまとめます。

  1. 並行処理:複数のタスクを切り替えながら「同時に扱う」ための構造。論理的な概念
  2. 並列処理:複数のタスクが物理的に同じ瞬間に実行されること。ハードウェアの問題
  3. シングルコアでも並行処理は可能。並列処理には複数のコアが必要
  4. 並行処理はコードの構造で作り、並列処理はその構造をハードウェアが活用した結果です

コーヒーマシン1台で理解する

バリスタが1人(コア1つ)だけいるカフェを想像してください。

2つの注文が入りました。バリスタはAさんのエスプレッソを抽出している間にBさんのミルクを温め、抽出が終わるとAのドリンクを仕上げ、またBに戻ります。2つの注文は「同時に進行中」ですが、どの瞬間を切り取ってもバリスタがしているのは1つの作業だけです。

これが並行処理です。作業を細かく分け、切り替えながら複数の仕事を扱う構造です。

バリスタをもう1人雇うと(コア2つ)、2つの注文が本当に同じ瞬間に作られます。これが並列処理です。

重要なのは、バリスタが1人でも「注文を交互に処理する運用方式」は成立し、2人になった瞬間に同じ方式が物理的な同時実行へ拡張されることです。


コンピューターに置き換えると

シングルコア時代のマルチタスクは、まさにバリスタ1人のカフェです。

OSは数十ミリ秒単位でCPUをプロセスごとに交互に割り当てます(タイムスライス)。そのため、人間には音楽の再生と文書編集が同時に動いているように見えました。

シングルコアのタイムスライスとマルチコアの同時実行を対比した並行処理・並列処理の図
シングルコアは交互に進行(タイムスライス)、マルチコアは同じ瞬間に実行

マルチコアになると並列処理が加わりました。今では4つのコアが同じ瞬間に4つのスレッドを実行できます。

関係を次のように整理してみましょう。

  • 並行処理なしの並列処理:互いに無関係なタスクをコアごとに1つずつ実行する場合
  • 並列処理なしの並行処理:シングルコアのタイムスライス
  • 並行処理+並列処理:現代コンピューティングの基本。分割したタスクを複数のコアが分担して実行

Go言語を作ったRob Pikeの有名な講演タイトルが、この違いを一文で要約しています。

「Concurrency is not parallelism(並行処理は並列処理ではない)。」

彼は、並行処理を複数のことを「扱うこと(dealing with)」、並列処理を複数のことを「実行すること(doing)」と区別しました。


Swift Concurrencyという名前の意味

この観点から見ると、Appleがasync/awaitの仕組みにSwift「Concurrency」と名付けたのは正確です。

async/await、Task、actorはすべて、「タスクをどう分割し、どこで中断し、どの順番で再開するか」を表現するツールです。つまり、並行処理の構造を設計するための言語機能です。

その構造を実際に何個のコアで並列実行するかは、ランタイムとシステムスケジューラーが決めます。開発者は構造(並行処理)を宣言し、並列実行はシステムが担うという役割分担です。

async let a = fetchProfile()   // 「同時に『進行できる』」構造を宣言
async let b = fetchFeed()
let result = try await (a, b)  // 並列に実行するかどうかはシステムが決める

TaskGroupで100個のタスクを作っても、コアが8つなら同じ瞬間に動くのは最大8個です。残りは交互に進みます。並行処理の構造内で得られる並列処理は、ハードウェアの範囲に限られます。

100個のタスクチップを8つのコアスロットに割り当てるスケジューラーのイラスト
並行処理の構造を宣言すると、並列実行するかどうかはシステムが決めます

面接で一文にまとめると

「並行処理は、複数のタスクを交互に進めながら一緒に扱う論理的な構造であり、並列処理は複数のタスクが物理的に同じ瞬間に実行されることです。したがって、シングルコアでも並行処理は可能ですが、並列処理は不可能です。」

追加質問にも備えておくとよいでしょう。「シングルコアのマルチタスクはどう可能だったか」(タイムスライス)、「並行処理コードは常に並列に動くか」(いいえ、スケジューラーが決める)などです。


まとめ

  • 並行処理は作業を分割して交互に進め、複数の仕事を一緒に扱う構造。論理レベルの概念です
  • 並列処理は複数のタスクが物理的に同じ瞬間に実行されること。ハードウェアレベルの概念です
  • シングルコアでも並行処理(タイムスライス)は可能ですが、並列処理は不可能です
  • Rob Pike:並行処理は複数のことを「扱うこと」、並列処理は複数のことを「実行すること」
  • Swift Concurrencyは並行処理の構造を宣言するツールで、実際の並列実行はシステムが決めます
  • コーヒーマシンのたとえ:1人のバリスタが交互に作れば並行処理、2人が一緒に作れば並列処理