2013-06-03 5 views
16

最近私は関数型言語について多くのことを読んできました。これらは不変構造のみを使用するため、並行性の問題が大幅に改善/解決されていると主張しています。私はこれが実際の状況でどのように実際に提供されるのかを深刻に理解しています。 1つのスレッドがポートでリッスンしているWebサーバーがあるとしましょう(IOは別のものですが、私の頭をラップするのは難しいですが、今は無視してみましょう)。接続の試行時に、ソケットが作成され、新しく作成されたスレッドに渡されます。新しく作成されたスレッドは、受信した通信に応じて、サーバーアプリケーションのグローバルな大きなリスト/データ構造に変更を適用します。したがって、リストの一貫性のあるビューを持つすべてのスレッド(または少なくとも、スレッドが正しい方法で終了するとすぐにリストに適用された1つのスレッドによって行われたすべての変更を行うために) ?不変型および永続型およびデータ構造を使用する並行性はどのように機能しますか?

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

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

は、どのようにあなたがそのようなことをモデル化するだろう、しかし、副作用に対処することができません関数型言語?

+0

ここでは、基本的な概念についての良い話です。http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey – buritos

+2

すでに2回見ましたが、残念ながら、まだそれを取得していません。関数型プログラミングの最大の問題は、1)ほとんどの人が命令型言語を学び訓練していること2)関数型言語は別の方法で考える必要があること3)関数型プログラミングを教えるリソースがないこと99%(= )信じられないほど単純な例を除いて – Askaga

+0

それは私も同様に来ているとそれは簡単ではないですね。私は、スレッドが他のスレッドの副作用を読み取る必要がある理由に答えることから始めます。私はちょうど私の旅を始めたと私はなぜ私は答えをしようとしないだろうと思う、私は確信している人の多くはこれにも答えます:-) – buritos

答えて

17

変更不可能な値には、適切ないくつかのアプリケーションがあります。並行/並行処理は、最近重要性を増しているものの1つに過ぎません。以下は、実際には経験からの最も基本的なダイジェストであり、そのテーマに関する多くの本や講演です。あなたは最終的にいくつかに潜り込む必要があるかもしれません。

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

  • 試み - あなたは不変の値で、修正ハーフウェイを残すことができる共有オブジェクトを変更しないので、キャッチは、はるかに良い振る舞い、それは自動的に最後の一貫性のある状態
  • を保ちます
  • 非常に限られたグローバル変数(理想的には1つ)のマルチコア安全な「比較とスワップ」操作に状態を変更すると、完全にデッドロックがなくなります。
  • 忘れてしまった不思議なバグ(開発者が「申し訳ありません」よりも安全性が高い」 FTERデバッグセッションのカップル)
  • はるかに簡単にユニットテスト、不変の値で動作する多くの機能は、通常、簡単にシリアライズし、より透明性の比較セマンティクス はるかに簡単にデバッグや服用(ログ)現在のスナップショット
  • 無料の副作用であるため、システム状態の非同期的にも

あなたの質問に戻る。

最も単純なケースでは、この場合のグローバル状態は、不変のデータ構造を保持している一番上の可変参照を使ってモデル化されることがよくあります。

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

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

2つのスレッド/コアが同時に同じスワップから新しい値を取得したい場合、最初のものが他のスレッドより優先され(CASのセマンティクス)、操作を繰り返す必要があります新しい値で現在の値を更新するか、最初から新しい値に変換する)。これは無駄に思えるかもしれませんが、ここでは、一部の作業をやり直すことは、永続的なロック/同期のオーバーヘッドより安いことが多いということです。もちろん、これは最適化することができます。いくつかの参照が独立して更新されることによって、潜在的な衝突をさらに減らすために、不変のデータ構造の独立した部分を分割することによって、

データ構造へのアクセスはロックフリーで非常に高速で、常に一貫した応答を提供します。あなたが更新を送信し、別のクライアントが後で古いデータを受け取るようなエッジの場合は、ネットワーク要求があまりにも乱れる可能性があるため、どのシステムでも期待されます...

STMはまれにしか役に立ちませんSTMトランザクションで使用する参照のすべての値を含むデータ構造のアトミックスワップを使用することです。

+1

非常に良い答えです。関数プログラミングに関するほとんどのチュートリアルでは、完全に無視されている(または間違って説明されている)ことについて多くの洞察を提供します。 – Askaga

+1

ありがとうございます。私は不変のデータに関して合併の問題への答えを見つけるために、現在数日の間にウェブサイトを捜し求めてきました。ほとんどのリソースは、 "[...]スレッドセーフであり、したがって、同時実行性に役立ちます。"、変更をマージするというより困難な問題に陥ることはありません。 – aefxx

+0

マップのようなデータ構造の例を取り上げると、このマップのような構造が不変で、それを同時に並行させたいのであれば、並行書き込み中に各キーと値のペアを独立したCAS操作にする必要はありませんか? – CMCDragonkai

関連する問題