new値を常に作成しているため、単一割り当ての不変データで作業すると、より多くのメモリが必要になるという明らかな影響があります(ただし、コンパイラカバーは、これを問題の少ないものにするためのポインタートリックを行います)。
しかし、パフォーマンスの低下が、CPU(具体的にはメモリコントローラー)がメモリが変化しないという事実を(それほど)活用できるという点で、利益よりも重要であると今まで何度か聞いたことがあります。
私は誰かがどうやってこれに当てはまるか(またはそうでない場合)に光を当てることができることを望んでいました。
別の投稿へのコメント で言及されました Abstract Data Types (ADT's)はこれと関係があるため、さらに興味深いことに、ADTは特にCPUの動作にどのように影響するのですか?メモリを扱いますか?ただし、これは余談ですが、ほとんどの場合、言語の純粋さがCPUやそのキャッシュなどのパフォーマンスにどのように影響を与えるかに興味があります。
CPU(具体的にはそのメモリコントローラ)は、メモリが変更されていないという事実を利用できます
利点は、この事実により、データにアクセスするときにコンパイラが membar 命令を使用しないようにすることです。
メモリバリアは、membar、メモリフェンス、またはフェンス命令とも呼ばれ、中央処理装置(CPU)またはコンパイラに、バリア命令の前後に発行されたメモリ操作に順序付け制約を強制する一種のバリア命令です。これは通常、特定の操作がバリアの前に実行され、他の操作が後に実行されることが保証されていることを意味します。
最近のほとんどのCPUは、順序が狂って実行される可能性のあるパフォーマンス最適化を採用しているため、メモリバリアが必要です。このメモリ操作(ロードとストア)の並べ替えは、通常、実行の単一スレッド内では気付かれませんが、注意深く制御しない限り、並行プログラムとデバイスドライバで予期しない動作を引き起こす可能性があります...
異なるスレッドからデータにアクセスすると、マルチコアCPUでは次のようになります。異なるスレッドは異なるコアで実行され、それぞれが独自の(コアに対してローカルな)キャッシュ-グローバルキャッシュのコピーを使用します。
データが変更可能であり、プログラマーが異なるスレッド間で一貫性を保つ必要がある場合、一貫性を保証するための対策を講じる必要があります。プログラマにとって、これは、特定のスレッドでデータにアクセス(たとえば、読み取り)するときに、同期構造を使用することを意味します。
コンパイラーの場合、コード内の同期構造は、コアの1つでデータのコピーに加えられた変更が適切に伝達(「公開」)されるようにするために、membar命令を挿入する必要があることを意味します。他のコアのキャッシュが同じ(最新の)コピーを持つことを保証します。
やや簡素化 下の注を参照、これがmembarのマルチコアプロセッサで何が起こるかです。
グローバルキャッシュとローカルキャッシュ間でデータがコピーされている間、すべてのコアは何も実行していません。これは、可変データが適切に同期されるようにするために必要です(スレッドセーフ)。 4つのコアがある場合、4つすべてが停止し、キャッシュが同期されている間待機します。 8つある場合、8つすべてが停止します。 16個ある場合...まあ、これらのいずれかで実行する必要のあるものを待っている間、15コアはまったく何もしません。
では、データが不変の場合はどうなるのでしょうか。どのスレッドがアクセスしても、同じであることが保証されています。プログラマにとって、これは不要特定のスレッドでデータにアクセス(読み取り)するときに同期構造を挿入することを意味します。
コンパイラの場合、これは不要membar命令を挿入することを意味します。
その結果、データへのアクセスは、コアを停止し、データがグローバルキャッシュとローカルキャッシュ間で書き込まれる間待機する必要がありません。これはメモリが変更されないという事実の利点です。
注やや簡略化上記の説明では、たとえば pipelining のように、データが変更可能であることによるいくつかのより複雑な悪影響を排除しています。必要な順序付けを保証するために、CPUはデータ変更の影響を受けるパイルラインを無効にする必要があります-これはさらに別のパフォーマンス上のペナルティです。これがすべてのパイプラインの単純な(したがって信頼性の高い)無効化によって実装される場合、マイナスの影響はさらに増幅されます。