並行コンピューティングとは、複数の計算を順次実行するのではなく、重複する時間帯に同時に実行するコンピューティングの一形態である。つまり、ある計算が完了する前に次の計算が開始されるという従来の方式とは異なる。
これは、プログラム、コンピュータ、ネットワークなど、システムの特性であり、各プロセスに個別の実行ポイントまたは「制御スレッド」が存在することを意味します。並行システムとは、他のすべての計算が完了するのを待たずに計算を進めることができるシステムのことです。[ 1 ]
並行コンピューティングは、モジュール型プログラミングの一形態です。そのパラダイムでは、全体的な計算が、並行して実行できるサブ計算に分割されます。並行コンピューティング分野の先駆者には、エドガー・ダイクストラ、ペル・ブリンチ・ハンセン、CAR・ホーアなどがいます。[ 2 ]
並行コンピューティングの概念は、関連するものの異なる概念である並列コンピューティングと混同されることが多い。[ 3 ] [ 4 ]どちらも「同じ期間に実行される複数のプロセス」と説明できるが、並列コンピューティングでは、実行は同じ物理的な瞬間に行われる。例えば、マルチプロセッサマシンの別々のプロセッサ上で、計算の高速化を目的として行われる。並列コンピューティングは、(1コアの)シングルプロセッサでは不可能である。なぜなら、どの瞬間(どのクロックサイクル)にも、1つの計算しか実行できないからである。[ a ]対照的に、並行コンピューティングは、プロセスのライフサイクルが重複するものの、実行は同じ瞬間には行われない。ここでの目的は、複数のクライアントが同時にサーバーにアクセスするなど、並行して発生するプロセスをモデル化することである。ソフトウェアシステムを、複数の並行して通信する部分で構成されるものとして構造化することは、各部分が並列に実行できるかどうかに関わらず、複雑さに対処する上で有用である。[ 5 ] : 1
例えば、同時実行プロセスは、タイムシェアリングスライスを用いて各プロセスの実行ステップをインターリーブすることで、1つのコア上で実行できます。一度に実行されるプロセスは1つだけであり、そのプロセスがタイムスライス内に完了しない場合は一時停止され、別のプロセスが開始または再開され、その後、元のプロセスが再開されます。このようにして、ある瞬間には複数のプロセスが実行途中の状態になりますが、その瞬間に実際に実行されているのは1つのプロセスのみです。
同時計算は並列に実行できます。 [ 3 ] [ 6 ]たとえば、各プロセスを個別のプロセッサまたはプロセッサコアに割り当てたり、ネットワーク全体に計算を分散したりすることによって実行できます。
並行システムにおけるタスクの実行タイミングはスケジューリングに依存し、タスクは必ずしも並行して実行されるとは限りません。例えば、2つのタスクT1とT2があるとします。
「シーケンシャル」という言葉は、「同時実行」と「並列実行」の両方の反意語として使われます。これらが明確に区別される場合、同時実行/シーケンシャル、並列実行/シリアルが反対のペアとして使われます。[ 7 ]タスクがインターリーブなしで(逐次的に、並列性なし、前のタスクが終了するまでタスクが開始されない)一度に 1 つずつ実行されるスケジュールは、シリアル スケジュールと呼ばれます。シリアルにスケジュールできるタスクのセットはシリアル化可能であり、これにより同時実行制御が簡素化されます。
並行プログラムを設計する際の主な課題は、並行性制御です。これは、異なる計算実行間の相互作用または通信の正しい順序を保証し、実行間で共有されるリソースへのアクセスを調整することです。[ 6 ]潜在的な問題には、競合状態、デッドロック、リソース枯渇などがあります。たとえば、共有リソースで表される当座預金口座から引き出しを行う次のアルゴリズムを考えてみましょうbalance。
bool withdraw ( int withdrawal ){if (残高>=引き出し額){残高-=引き出し;return true ;}falseを返します。}と仮定しbalance = 500、2 つの同時実行スレッドが と を呼び出すとしますwithdraw(300)。withdraw(350)両方の操作の 3 行目が 5 行目より先に実行されると、両方の操作で が とbalance >= withdrawal評価されtrue、実行は引き出し額の減算に進みます。しかし、両方のプロセスが引き出しを実行するため、最終的に引き出される合計金額は元の残高よりも多くなります。このような共有リソースの問題は、並行性制御、つまりノンブロッキングアルゴリズムを使用することで解決できます。
並行コンピューティングには以下のような利点があります。
1962年に導入されたペトリネットは、並行実行のルールを体系化しようとする初期の試みでした。データフロー理論は後にこれらを基に発展し、データフローアーキテクチャはデータフロー理論の理念を物理的に実装するために開発されました。1970年代後半からは、相互作用するコンポーネントで構成されるシステムについて代数的に推論できるように、通信システム計算( CCS)や通信逐次プロセス(CSP)などのプロセス計算が開発されました。π計算は、動的なトポロジーについて推論する機能を追加しました。
入出力オートマトンが1987年に導入された。
並行システムの挙動を記述するために、ランポートのTLA+のような論理体系や、トレースやアクターイベント図のような数学モデルも開発されてきた。
ソフトウェア・トランザクショナル・メモリは、データベース理論からアトミック・トランザクションの概念を借用し、それをメモリ・アクセスに適用する。
並行プログラミング言語やマルチプロセッサプログラムは、一貫性モデル(メモリモデルとも呼ばれる)を備えている必要があります。一貫性モデルは、コンピュータメモリに対する操作がどのように行われ、結果がどのように生成されるかに関する規則を定義します。
最初の一貫性モデルの1つは、レスリー・ランポートの逐次一貫性モデルでした。逐次一貫性とは、プログラムの実行結果が逐次プログラムと同じになるというプログラムの特性です。具体的には、「任意の実行結果が、すべてのプロセッサの操作が何らかの順序で実行された場合と同じであり、各プロセッサの操作がそのプログラムで指定された順序でこのシーケンスに現れる場合」に、プログラムは逐次一貫性を持つと言えます。[ 10 ]
並行プログラムを実装するには、さまざまな方法が利用できます。例えば、各計算処理をオペレーティングシステムのプロセスとして実装する方法や、単一のオペレーティングシステムのプロセス内で計算処理をスレッドの集合として実装する方法などがあります。
並行コンピューティングシステムの中には、並行コンポーネント間の通信がプログラマから隠蔽されているもの(例えば、フューチャーを使用するなど)もあれば、明示的に処理する必要があるものもある。明示的な通信は、大きく2つのクラスに分類できる。
共有メモリとメッセージパッシングの並行処理は、パフォーマンス特性が異なります。一般的に(常にではありませんが)、プロセスごとのメモリオーバーヘッドとタスク切り替えオーバーヘッドはメッセージパッシングシステムの方が低くなりますが、メッセージパッシング自体のオーバーヘッドはプロシージャ呼び出しよりも大きくなります。これらの違いは、他のパフォーマンス要因によって相殺されることがよくあります。
並列コンピューティングは、19世紀から20世紀初頭にかけての鉄道や電信に関する研究から発展したものであり、信号機などの用語もこの時代に由来する。これらは、同じ鉄道システム上で複数の列車をどのように処理するか(衝突を回避し、効率を最大化する)、また、時分割多重化(1870年代)などによって、与えられた一連の電線を通して複数の伝送をどのように処理するか(効率を向上させる)という問題に対処するために生まれた。
並行アルゴリズムの学術研究は1960年代に始まり、ダイクストラ(1965)はこの分野で最初の論文を発表し、相互排他を特定して解決したとされている。[ 12 ]
並列処理はコンピューティングにおいて広く普及しており、単一チップ上の低レベルハードウェアから世界規模のネットワークまで、あらゆる場面で発生している。以下に例を挙げる。
プログラミング言語レベルでは:
オペレーティングシステムレベルでは:
ネットワークレベルでは、ネットワークシステムは一般的に、個別のデバイスで構成されているため、その性質上、並行処理を行う。
並行プログラミング言語とは、並行処理のための言語構造を用いるプログラミング言語のことです。これらの構造には、マルチスレッド、分散コンピューティングのサポート、メッセージパッシング、共有リソース(共有メモリを含む)、フューチャーやプロミスなどが含まれる場合があります。このような言語は、並行処理指向言語または並行処理指向プログラミング言語(COPL)と呼ばれることもあります。 [ 13 ]
現在、並行処理のための特定の構造を持つプログラミング言語として最も一般的に使用されているのは、JavaとC#です。これらの言語はどちらも基本的に共有メモリ型の並行処理モデルを採用しており、ロックはモニターによって提供されます(ただし、基盤となる共有メモリ型モデルの上にメッセージパッシング型モデルを実装することも可能ですし、実際に実装されています)。メッセージパッシング型の並行処理モデルを採用している言語の中で、 2010年時点ではErlangが業界で最も広く使用されていたと考えられます。
多くの並行プログラミング言語は、実運用向けというよりは研究用言語(例: Pict )として開発されてきました。しかし、 Erlang、Limbo、Occamといった言語は、過去20年間で様々な時期に産業界で利用されてきました。並行プログラミング機能を利用する、あるいは提供する言語の例を以下に挙げます(ただし、これらに限定されません)。
他の多くのプログラミング言語も、ライブラリの形で並行処理をサポートしており、そのレベルは上記のリストとほぼ同等である。