一般的なルールとして、関数型プログラミングはより高速なプログラムを作成しません。それにより、並列および並行プログラミングが容易になります。これには2つの主要なキーがあります。
- 可変状態の回避は、プログラムで問題を起こす可能性のあるものの数を減らす傾向があり、並行プログラムではさらにそうなります。
- 共有メモリおよびロックベースの同期プリミティブを回避してより高いレベルの概念を支持すると、コードのスレッド間の同期が簡素化される傾向があります。
ポイント#2の一つの優れた例は、Haskellで、我々は明確に区別持っていることである決定論的並列処理対非決定論的同時実行を。Simon Marlowの著書 『Haskellでの並列および並行プログラミング』を引用するよりも良い説明はありません(引用は第1章からです)。
並列プログラムをより迅速に計算を実行する計算ハードウェア(例えば、いくつかのプロセッサコア)の多数を使用するものです。目的は、計算の異なる部分を同時に実行する異なるプロセッサに委任することにより、より早く答えに到達することです。
対照的に、並行性は、複数の制御スレッドがあるプログラム構造化手法です。概念的には、制御のスレッドは「同時に」実行されます。つまり、ユーザーには効果が交互に表示されます。実際に同時に実行するかどうかは、実装の詳細です。並行プログラムは、インターリーブされた実行を通じて単一のプロセッサで実行することも、複数の物理プロセッサで実行することもできます。
これに加えて、Marlowは、決定論の次元も取り上げています。
関連する区別は、確定的プログラミングモデルと非確定的プログラミングモデルです。決定論的プログラミングモデルは、各プログラムが1つの結果のみを提供できるモデルです。一方、非決定論的プログラミングモデルは、実行のいくつかの側面に応じて異なる結果をもたらす可能性があるプログラムを受け入れます。同時プログラミングモデルは、予測できない時間にイベントを発生させる外部エージェントと対話する必要があるため、必然的に非決定的です。ただし、非決定性にはいくつかの顕著な欠点があります。プログラムのテストと推論が非常に難しくなります。
並列プログラミングでは、可能な限り決定論的プログラミングモデルを使用します。目標は、より迅速に答えに到達することであるため、プロセスでデバッグを難しくすることは避けたいと考えています。決定論的並列プログラミングは両方の長所です。テスト、デバッグ、推論はシーケンシャルプログラムで実行できますが、プロセッサを追加するとプログラムは高速に実行されます。
Haskellでは、これらの概念に基づいて並列処理と同時実行機能が設計されています。特に、他の言語が1つの機能セットとしてグループ化されている場合、Haskellは2つに分割されます。
- 並列性のための決定論的な機能とライブラリ。
- 並行性のための非決定的機能とライブラリ。
純粋な決定論的計算を高速化しようとしている場合、決定論的並列処理を使用すると、多くの場合、作業がはるかに簡単になります。多くの場合、次のようなことを行うだけです。
- 回答のリストを作成する関数を作成します。それぞれの回答は計算に費用がかかりますが、互いにあまり依存しません。これはHaskellなので、リストは遅延します。要素の値は、消費者が要求するまで実際には計算されません。
- Strategiesライブラリを使用して、関数の結果リストの要素を複数のコアにわたって並行して使用します。
数週間前におもちゃプロジェクトプログラムで実際にこれをしました。プログラムを並列化するのは簡単でした。私がしなければならなかった重要なことは、「このリストの要素を並列で計算する」というコードを追加することでした(90行目)。私のより高価なテストケースのいくつか。
プログラムは、従来のロックベースのマルチスレッドユーティリティを使用した場合よりも高速ですか?私はとても疑っています。私の場合のきちんとしたことは、ほんのわずかな費用で大きな成果を上げたことです。コードはおそらく非常に最適ではありませんが、並列化が非常に簡単なため、適切にプロファイリングして最適化するよりもはるかに少ない労力で大きなスピードアップが得られました。競合状態のリスクはありません。そして、それが、関数型プログラミングが「より高速な」プログラムを書くことを可能にする主な方法だと私は主張します。