18

最近、関数型言語についてよく読んでいます。それらは不変の構造のみを使用するため、同時実行性の問題が大幅に改善/解決されると主張しています。これが実際の状況で実際にどのように配信されるかを理解するのに深刻な問題があります。1 つのスレッドがポートをリッスンしている Web サーバーがあるとします (まあ、IO は頭を悩ませるもう 1 つの問題ですが、今は無視しましょう)。接続が試行されるたびに、ソケットが作成され、新しく作成されたスレッドに渡されます。スレッドはそれを処理し、受信した通信に応じて、サーバー アプリケーションにグローバルな大きなリスト/データ構造に変更を適用する場合があります。そう、

私の理解の問題は次のとおりです。

  • 明らかに、どのスレッドでも、作業対象のリストの変更不可能な「スナップショット」を取得できます。ただし、変更が適用されたリストの新しいバージョンを作成して内容を「変更」した後でも、すべてのスレッドに独自のバージョンのリストが残っています。それらはどのようにマージされますか?
  • 別の方法として、mutex/cond や go-like-channel などの従来のロック メカニズムを使用する方法があります。しかし、すべての変数が不変である場合、どのようにしてそのようなものを作成するのでしょうか?
  • STMについて聞いたことがありますが、それは副作用に対処できません(つまり、リストがデータをファイルまたはデータベースに透過的にバックアップする場合)

では、そのようなことを関数型言語でどのようにモデル化しますか?

4

1 に答える 1

20

不変値には、それらが適している用途がいくつかあります。並行/並列処理は、最近重要性が増したものの 1 つにすぎません。以下は、実際の経験と、このテーマに関する多くの本や講演からの最も基本的なダイジェストです。最終的には、いくつかに飛び込む必要があるかもしれません。

ここで示す主な例は、グローバル状態の管理に関するものであるため、純粋に「不変」に行うことはできません。ただし、ここでも、不変のデータ構造を使用する十分な理由があります。私の頭の上からのいくつか:

  • try - 不変の値を使用して途中で変更されたままになる可能性のある共有オブジェクトを変更しないため、catch の動作が大幅に改善され、最後の一貫性のある状態が自動的に保持されます。
  • グローバル変数の非常に限られたセット (理想的には 1 つ) で、状態の変更をマルチコアの安全な「比較と交換」操作に減らし、デッドロックを完全に排除します。
  • 防御的なコピーなしでデータ構造を自由に渡すことは、忘れられたときに謎のバグになることがよくあります (多くの場合、防御的なコピーは、呼び出し関数と呼び出された関数の両方で作成されます。セッション)
  • 不変値で動作する多くの関数は副作用がないため、単体テストがはるかに簡単になります
  • 通常、シリアライゼーションが容易になり、比較セマンティクスがより透過的になる デバッグがはるかに容易になり、非同期であってもシステム状態の現在のスナップショットを取得 (ロギング) する

ただし、質問に戻ります。

最も些細なケースでは、この場合のグローバル状態は、多くの場合、不変のデータ構造を保持する 1 つの可変参照を使用してモデル化されます。

参照は、CAS アトミック操作によってのみ更新されます。

不変のデータ構造は、副作用のない関数によって変換され、すべての変換が完了すると、参照がアトミックに交換されます。

2 つのスレッド/コアが同じ古い値から取得した新しい値を同時に交換したい場合、最初にそれを行った方が他方を勝ち取り (CAS セマンティクス)、操作を繰り返す必要があります (変換に応じて、現在の値を更新するか、変換に依存します)。新しい値を使用するか、最初から新しい値を変換します)。これは無駄に思えるかもしれませんが、ここでの前提は、いくつかの作業をやり直すことは、多くの場合、永続的なロック/同期のオーバーヘッドよりも安価であるということです。

もちろん、これは最適化できます。たとえば、不変データ構造の独立した部分を分割して、複数の参照を個別に更新することで衝突の可能性をさらに減らします。

データ構造へのアクセスはロックフリーで非常に高速で、常に一貫した応答を返します。更新を送信し、別のクライアントが後で古いデータを受信した場合などのエッジケースは、ネットワークリクエストが故障する可能性があるため、どのシステムでも予想されます...

STM が役立つことはめったになく、通常は、STM トランザクションで使用する参照からのすべての値を含むデータ構造のアトミック スワップを使用することをお勧めします。

于 2013-06-10T12:20:02.463 に答える