並行コンピューティングとは、複数の計算を順次実行するのではなく、重複する時間帯に同時に実行するコンピューティングの一形態である。つまり、ある計算が完了する前に次の計算が開始されるという従来の方式とは異なる。
これは、プログラム、コンピュータ、ネットワークなど、システムの特性であり、各プロセスに個別の実行ポイントまたは「制御スレッド」が存在することを意味します。並行システムとは、他のすべての計算が完了するのを待たずに計算を進めることができるシステムのことです。[ 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つのクラスに分類できる。
共有メモリとメッセージパッシングの並行処理は、パフォーマンス特性が異なります。一般的に(常にではありませんが)、プロセスごとのメモリオーバーヘッドとタスク切り替えオーバーヘッドはメッセージパッシングシステムの方が低くなりますが、メッセージパッシング自体のオーバーヘッドはプロシージャ呼び出しよりも大きくなります。これらの違いは、他のパフォーマンス要因によって相殺されることがよくあります。
Concurrent computing developed out of earlier work on railroads and telegraphy, from the 19th and early 20th century, and some terms date to this period, such as semaphores. These arose to address the question of how to handle multiple trains on the same railroad system (avoiding collisions and maximizing efficiency) and how to handle multiple transmissions over a given set of wires (improving efficiency), such as via time-division multiplexing (1870s).
The academic study of concurrent algorithms started in the 1960s, with Dijkstra (1965) credited with being the first paper in this field, identifying and solving mutual exclusion.[12]
Concurrency is pervasive in computing, occurring from low-level hardware on a single chip to worldwide networks. Examples follow.
At the programming language level:
At the operating system level:
At the network level, networked systems are generally concurrent by their nature, as they consist of separate devices.
Concurrent programming languages are programming languages that use language constructs for concurrency. These constructs may involve multi-threading, support for distributed computing, message passing, shared resources (including shared memory) or futures and promises. Such languages are sometimes described as concurrency-oriented languages or concurrency-oriented programming languages (COPL).[13]
Today, the most commonly used programming languages that have specific constructs for concurrency are Java and C#. Both of these languages fundamentally use a shared-memory concurrency model, with locking provided by monitors (although message-passing models can and have been implemented on top of the underlying shared-memory model). Of the languages that use a message-passing concurrency model, Erlang was probably the most widely used in industry as of 2010.
多くの並行プログラミング言語は、実運用向けというよりは研究用言語(例: Pict )として開発されてきました。しかし、 Erlang、Limbo、Occamといった言語は、過去20年間で様々な時期に産業界で利用されてきました。並行プログラミング機能を利用する、あるいは提供する言語の例を以下に挙げます(ただし、これらに限定されません)。
他の多くのプログラミング言語も、ライブラリの形で並行処理をサポートしており、そのレベルは上記のリストとほぼ同等である。