同時実行コンピューティングとは、複数の計算を順番に実行するのではなく、重複する期間に同時に実行し、1 つの計算が完了してから次の計算を開始する コンピューティング形式です。
これは、プログラム、コンピュータ、ネットワークなど、各プロセスに個別の実行ポイント、つまり「制御スレッド」が存在するシステムの特性です。並行システムとは、他のすべての計算が完了するのを待たずに計算を進めることができるシステムのことです。[1]
並行コンピューティングはモジュールプログラミングの一形態です。そのパラダイムでは、全体的な計算が並行して実行可能なサブ計算に分割されます。並行コンピューティング分野の先駆者には、エドガー・ダイクストラ、ペル・ブリンチ・ハンセン、CAR・ホーアなどがいます。[2]
同時計算の概念は、関連しているものの異なる概念である並列計算としばしば混同されます[ 3] [4]。ただし、どちらも「複数のプロセスが同時に実行される」と説明できます。並列計算では、実行は物理的に同じ瞬間に行われます。例えば、マルチプロセッサマシンの別々のプロセッサ上で、計算の高速化を目的として実行されます。並列計算は、(1コアの)単一プロセッサでは不可能です。なぜなら、どの瞬間(どのクロックサイクルでも)にも1つの計算しか実行できないからです。[a]一方、同時計算では、プロセスの存続期間が重なり合いますが、実行は同時には行われません。ここでの目標は、複数のクライアントが同時にサーバーにアクセスするように、同時に発生するプロセスをモデル化することです。ソフトウェアシステムを、複数の同時かつ通信する部分で構成されるものとして構造化することは、各部分が並列実行可能かどうかに関わらず、複雑さに対処するのに役立ちます。[5] : 1
例えば、各プロセスの実行ステップをタイムシェアリングスライスでインターリーブすることで、1つのコアで複数のプロセスを並行して実行できます。つまり、一度に実行されるプロセスは1つだけで、そのタイムスライス内で完了しない場合は一時停止され、別のプロセスが開始または再開され、その後、元のプロセスが再開されます。このように、ある瞬間に複数のプロセスが実行の途中にある場合でも、その瞬間に実行されているのは1つのプロセスだけです。[要出典]
同時計算は、例えば各プロセスを別々のプロセッサまたはプロセッサコアに割り当てたり、計算をネットワーク全体に 分散したりすることによって並列に実行することができる[3] [6] 。
並行システムにおけるタスクの実行タイミングはスケジューリングに依存し、必ずしも同時に実行される必要はない。例えば、2つのタスクT1とT2があるとする。[要出典]
The word "sequential" is used as an antonym for both "concurrent" and "parallel"; when these are explicitly distinguished, concurrent/sequential and parallel/serial are used as opposing pairs.[7] A schedule in which tasks execute one at a time (serially, no parallelism), without interleaving (sequentially, no concurrency: no task begins until the prior task ends) is called a serial schedule. A set of tasks that can be scheduled serially is serializable, which simplifies concurrency control.[citation needed]
The main challenge in designing concurrent programs is concurrency control: ensuring the correct sequencing of the interactions or communications between different computational executions, and coordinating access to resources that are shared among executions.[6] Potential problems include race conditions, deadlocks, and resource starvation. For example, consider the following algorithm to make withdrawals from a checking account represented by the shared resource balance:
bool withdraw(int withdrawal)
{
if (balance >= withdrawal)
{
balance -= withdrawal;
return true;
}
return false;
}
Suppose balance = 500, and two concurrent threads make the calls withdraw(300) and withdraw(350). If line 3 in both operations executes before line 5 both operations will find that balance >= withdrawal evaluates to true, and execution will proceed to subtracting the withdrawal amount. However, since both processes perform their withdrawals, the total amount withdrawn will end up being more than the original balance. These sorts of problems with shared resources benefit from the use of concurrency control, or non-blocking algorithms.
There are advantages of concurrent computing:
1962年に導入されたペトリネットは、並行実行のルールを体系化する初期の試みでした。後にデータフロー理論はペトリネットを基盤として発展し、データフロー理論の考え方を物理的に実装するためにデータフローアーキテクチャが開発されました。1970年代後半からは、相互作用するコンポーネントで構成されるシステムについて代数的推論を可能にするために、通信システム計算(CCS)や通信逐次プロセス(CSP)などのプロセス計算が開発されました。π計算は、動的なトポロジーに関する推論機能を追加しました。
入出力オートマトンが 1987 年に導入されました。
並行システムの動作を記述するために、 Lamport のTLA+などのロジックや、トレースやアクター イベント ダイアグラムなどの数学モデルも開発されてきました。
ソフトウェア トランザクショナル メモリは、データベース理論からアトミック トランザクションの概念を借用し、それをメモリ アクセスに適用します。
並行プログラミング言語とマルチプロセッサプログラムには、整合性モデル(メモリモデルとも呼ばれます)が必要です。整合性モデルは、コンピュータメモリ上での操作がどのように行われ、結果がどのように生成されるかについての規則を定義します。
最初の一貫性モデルの一つは、レスリー・ランポートの逐次一貫性モデルでした。逐次一貫性とは、プログラムの実行結果が逐次プログラムと同じ結果になるという性質です。具体的には、「すべてのプロセッサの処理が特定の順序で実行された場合と、各プロセッサの処理がプログラムで指定された順序で実行された場合とで、どの実行結果も同じになる」場合、プログラムは逐次一貫性があると言えます。[10]
並行プログラムを実装するには、各計算実行をオペレーティング システム プロセスとして実装したり、計算プロセスを単一のオペレーティング システム プロセス内の 一連のスレッドとして実装するなど、さまざまな方法を使用できます。
並行コンピューティングシステムの中には、並行コンポーネント間の通信がプログラマから隠蔽されているもの(例えば、futuresの使用など)もあれば、明示的に処理する必要があるものもあります。明示的な通信は、以下の2つのクラスに分けられます。
共有メモリとメッセージパッシングの同時実行性には、異なるパフォーマンス特性があります。一般的に(常にそうとは限りませんが)、メッセージパッシングシステムではプロセスごとのメモリオーバーヘッドとタスクスイッチングオーバーヘッドは低くなりますが、メッセージパッシングのオーバーヘッドはプロシージャ呼び出しよりも大きくなります。これらの違いは、他のパフォーマンス要因によって打ち消されることがよくあります。
並行コンピューティングは、19世紀から20世紀初頭にかけての鉄道と電信に関する研究から発展しました。セマフォなど、この時代に遡る用語もいくつかあります。これらは、同じ鉄道システム上で複数の列車をどのように処理するか(衝突を回避し、効率を最大化すること)、そして時分割多重化(1870年代)などによって、与えられた一連の回線上で複数の伝送をどのように処理するか(効率を向上させること)という問題に対処するために生まれました。
並行アルゴリズムの学術的研究は1960年代に始まり、ダイクストラ(1965)が相互排除を特定して解決するこの分野で最初の論文を発表したとされています。[11]
同時実行性はコンピューティングのあらゆる分野に浸透しており、単一チップ上の低レベルハードウェアから世界規模のネットワークに至るまで、多岐にわたります。以下に例を挙げます。
プログラミング言語レベル:
オペレーティング システム レベル:
ネットワーク レベルでは、ネットワーク システムは個別のデバイスで構成されているため、通常はその性質上並行です。
並行プログラミング言語とは、並行性のための言語構造を用いるプログラミング言語です。これらの構造には、マルチスレッド、分散コンピューティングのサポート、メッセージパッシング、共有リソース(共有メモリを含む)、FuturesとPromiseなどが含まれます。このような言語は、並行性指向言語または並行性指向プログラミング言語(COPL)と呼ばれることもあります。[12]
現在、並行処理に特化した構造を持つ最も一般的に使用されているプログラミング言語は、JavaとC#です。どちらの言語も基本的に共有メモリ型の並行処理モデルを採用しており、ロック機能はモニターによって提供されます(ただし、メッセージパッシングモデルは基盤となる共有メモリモデル上に実装可能であり、実際に実装されています)。メッセージパッシング型の並行処理モデルを使用する言語の中で、 2010年時点ではErlangがおそらく業界で最も広く使用されていました。[要出典]
多くの並行プログラミング言語は、実稼働用言語というよりも、研究用言語(例:Pict )として開発されてきました。しかしながら、 Erlang、Limbo、occamといった言語は、過去20年間で様々な時期に産業用途で利用されてきました。並行プログラミング機能を使用または提供する言語の一覧(網羅的ではありません)は以下のとおりです。
他の多くの言語では、上記のリストとほぼ同等のレベルで、ライブラリの形で並行性のサポートを提供しています。