9

最近では、ロックを使用せず、Erlang のようなメッセージ パッシング アプローチを使用することが話題になっています。または、関数型プログラミングと C++/Java のような不変データ構造の使用について。

ただ、気になるのは以下の点です。

  1. 私の知る限り、Erlang はメッセージの配信を保証しません。メッセージが失われる可能性があります。メッセージの損失を心配する必要がある場合、アルゴリズムとコードが肥大化し、再び複雑になることはありませんか? 使用する分散アルゴリズムは、メッセージの配信保証に依存してはなりません。
  2. Message が複雑なオブジェクトの場合はどうなるでしょうか? メッセージをコピーして送信する場合と、メッセージを共有の場所 (両方のプロセスがアクセスできる DB など) に保持する場合とでは、パフォーマンスが大幅に低下しませんか?
  3. 共有状態を本当に完全になくすことができますか? 私はそうは思わない。たとえば、DB では、同じレコードにアクセスして変更する必要があります。そこではメッセージパッシングを使用できません。ロックするか、Optimistic 同時実行制御メカニズムを想定してから、エラーのロールバックを行う必要があります。Mnesia はどのように機能しますか?
  4. また、常に並行性について心配する必要があるわけではありません。どのプロジェクトにも、同時実行性やトランザクションをまったく処理する必要のない大きなコードが含まれます (ただし、パフォーマンスと速度が懸念されます)。これらのアルゴリズムの多くは、共有状態に依存しています (そのため、参照渡しまたはポインターが非常に便利です)。

この事実を考えると、Erlang などでプログラムを作成することは、これらのことを行うことができないため苦痛です。おそらく、それはプログラムを堅牢にしますが、線形計画問題の解決や凸包の計算などの場合、パフォーマンスがより重要であり、並行性/トランザクションとは関係がない場合にアルゴリズムに不変性などを強制することは悪い決定です. ではない?

4

7 に答える 7

7
  1. それは現実です。言語/プラットフォームに関係なく、この可能性を考慮する必要があります。分散した世界 (現実の世界) では、物事は失敗します。

  2. もちろん、コストがかかります。私たちの宇宙には無料のものはありません。しかし、通信パイプで「大きなオブジェクト」をやり取りする代わりに、別のメディア (ファイル、データベースなど) を使用するべきではありませんか? 「メッセージ」を使用して、どこかに保存されている「大きなオブジェクト」をいつでも参照できます。

  3. もちろんそうではありません: 関数型プログラミング/Erlang OTP の背後にある考え方は、「共有状態」が操作された領域を可能な限り「分離」することです。さらに、共有状態が変更された場所を明確にマークすることで、テスト容易性と追跡可能性が向上します。

  4. あなたは要点を見落としていると思います。特効薬などというものはありません。Erlang を使用してアプリケーションを正常にビルドできない場合は、それを行わないでください。システム全体の他の部分をいつでも別の方法で、つまり別の言語/プラットフォームを使用できます。この点では、Erlang は他の言語と何ら変わりはありません。適切な仕事には適切なツールを使用してください

覚えておいてください: Erlang は、同時実行非同期、および分散の問題を解決できるように設計されています。たとえば、メモリの共有ブロックで効率的に作業するために最適化されていません...nifゲームの共有ブロック部分で動作する関数とのインターフェースを数えない限り:-)

于 2009-11-27T19:33:27.977 に答える
3

あなたの質問にはいくつかの暗黙の仮定があります.すべてのデータが1台のマシンに収まり、アプリケーションは本質的に1つの場所にローカライズされていると仮定しています.

アプリケーションが大きすぎて 1 台のマシンに収まらない場合はどうなりますか? アプリケーションが 1 台のマシンを超えるとどうなりますか?

アプリケーションが 1 台のマシンに適合する場合は 1 つの方法でプログラミングし、1 台のマシンでは収まらなくなったらすぐにまったく異なるプログラミング方法を使用する必要はありません。

フォールト トレラントなアプリケーションを作成したい場合はどうなりますか? 耐障害性を持たせるには、少なくとも 2 台の物理的に分離されたマシンが必要で、共有は必要ありません。共有とデータベースについて話すとき、MySQL クラスターのようなものは、物理的に離れたマシンでデータの同期されたコピーを維持することによって正確にフォールト トレランスを実現することを省略します。表面 - Erlang はこれを公開するだけです。

フォールト トレランスとスケーラビリティに対応するために、プログラムの方法を突然変更するべきではありません。

Erlang は、主にフォールト トレラントなアプリケーションを構築するために設計されました。

マルチコアの共有データには、独自の問題があります。共有データにアクセスするときは、ロックを取得する必要があります。グローバル ロックを使用すると (最も簡単な方法)、共有データにアクセスしている間にすべてのコアが停止する可能性があります。データ。マルチコアでの共有データ アクセスは、キャッシングの問題が原因で問題になる可能性があります。コアにローカル データ キャッシュがある場合、「遠く離れた」データ (他のプロセッサ キャッシュ内) にアクセスすると、非常にコストがかかる可能性があります。

多くの問題は本質的に分散しており、データが 1 つの場所で同時に利用できることはありません。この種の問題は、Erlang の考え方にうまく適合します。

分散設定では、「メッセージ配信の保証」は不可能です。送信先のマシンがクラッシュした可能性があります。したがって、Erlang はメッセージの配信を保証できません - 別のアプローチを取ります - メッセージの配信に失敗したかどうかをシステムが教えてくれます (ただし、リンクメカニズムを使用した場合のみ) - その後、独自のカスタムエラー回復を書くことができます)。

純粋な数値処理には Erlang は適切ではありませんが、ハイブリッド システムでは、Erlang は計算が利用可能なプロセッサに分散される方法を管理するのに優れているため、Erlang が問題の分散とフォールト トレラントな側面を管理する多くのシステムを目にしますが、問題自体は別の言語で解決さ​​れます。

他の言語が使用されている

于 2009-11-30T14:55:30.487 に答える
3

とにかく、実世界のシステムは常にハイブリッドです。現代のパラダイムが実際には、可変データと共有状態を取り除こうとしているとは思いません。

ただし、目的は、この共有状態への同時アクセスを必要としないことです。プログラムは並行部分と順次部分に分けることができ、並行部分にはメッセージパッシングと新しいパラダイムを使用できます。

すべてのコードが同じ投資を受けるわけではありません: スレッドは根本的に「有害と見なされる」という懸念があります。Apache のようなものは、従来の並行スレッドと、完全な並行共有状態で爆破できるように、何年にもわたって慎重に洗練されたテクノロジーの重要な部分を必要とする場合があります。オペレーティング システム カーネルは、「問題がどんなに高価であっても問題を解決する」ことが理にかなっているもう 1 つの例です。

fast-but-broken にメリットはありません: しかし、新しいコードやあまり注目されていないコードの場合、単純にスレッドセーフではなく、真の並行性を処理できない可能性があります。したがって、相対的な「効率」は関係ありません。1 つの方法は機能し、1 つの方法は機能しません。

テスト容易性を忘れないでください。また、テストにどのような価値を置けるでしょうか? スレッドベースの共有メモリの同時実行性は、単純にテストできません。メッセージパッシングの同時実行性は. つまり、1 つのパラダイムをテストできるが、もう 1 つのパラダイムはテストできないという状況になっています。では、コードがテスト済みであることを知ることの価値は何でしょうか? 他のコードがすべての状況で機能するかどうかさえわからないことの危険性?

于 2009-11-27T19:32:26.203 に答える
3

Erlang についての誤解について、いくつかコメントします。

  • Erlang は、メッセージが失われないこと、およびメッセージが送信された順序で到着することを保証します。 基本的なエラー状況は、マシン A がマシン B と通信できないことです。これが発生すると、プロセス モニターとリンクがトリガーされ、システム ノードダウン メッセージが登録されたプロセスに送信されます。黙って落とされることはありません。プロセスは「クラッシュ」し、スーパーバイザー (存在する場合) はそれらを再起動しようとします。
  • オブジェクトは変更できないため、常にコピーされます。不変性を確保する 1 つの方法は、値を他の erlang プロセスのヒープにコピーすることです。別の方法は、オブジェクトを共有ヒープに割り当て、それらへのメッセージ参照を割り当て、単純にそれらを変更する操作を行わないようにすることです。Erlang は最初のパフォーマンスを実現します! 共有ヒープをガベージ コレクションするためにすべてのプロセスを停止する必要がある場合は、リアルタイム性が損なわれます。ジャバに聞いてください。
  • Erlang には共有状態があります。Erlang はそれを誇りに思っていませんが、実用的です。1 つの例は、名前をプロセスにマップするグローバル マップであるローカル プロセス レジストリです。これにより、システム プロセスを再起動して古い名前を要求できます。Erlangは、可能であれば共有状態を回避しようとします。公開されている ETS テーブルは別の例です。
  • はい、Erlang が遅すぎる場合があります。これはすべての言語で発生します。Java が遅すぎる場合があります。C++ が遅すぎる場合があります。深刻な SIMD ベースのベクトル演算を開始するために、ゲームのタイトなループをアセンブリに落とし込まなければならなかったからといって、すべてがアセンブリで記述されるべきであると推測することはできません。重要なのは、優れたパフォーマンスを持つシステムを作成できることであり、Erlang は非常にうまく機能します。yaws または rabbitmq のベンチマークを参照してください。

あなたの事実はErlangに関する事実ではありません。Erlang プログラミングは面倒だと思っていても、Erlang のおかげで素晴らしいソフトウェアを作成する人がいることに気付くはずです。Erlang で IRC サーバーを作成するか、非常に並行して作成する必要があります。Erlang を二度と使用しないとしても、並行性について別の考え方を学んだはずです。しかしもちろん、Erlang は非常に簡単なので、そうするでしょう。

Erlang を理解していない人は、Erlang をうまく再実装しない運命にあります。

オーケー、オリジナルは Lisp に関するものでしたが... 本当です!

于 2009-11-27T22:30:24.403 に答える
1

たとえばDBでは、同じレコードにアクセスして変更する必要があります

しかし、それはDBによって処理されます。データベースのユーザーとしてクエリを実行するだけで、データベースはそれが分離して実行されることを保証します。

パフォーマンスに関しては、共有状態をなくすことで最も重要なことの 1 つは、新しい最適化が可能になることです。共有状態は特に効率的ではありません。コアが同じキャッシュ ラインをめぐって争うことになり、そうでなければレジスタまたは CPU キャッシュに留まる可能性があるメモリにデータを書き込む必要があります。

多くのコンパイラの最適化は、副作用の欠如と共有状態にも依存しています。

これらのことを保証するより厳密な言語は、C のようなものよりもパフォーマンスを向上させるために多くの最適化を必要とすると言えますが、コンパイラがこれらの最適化をはるかに簡単に実装できるようにもなります。

シングルスレッド コードでは、同時実行の問題と同様の多くの問題が発生します。最新の CPU はパイプライン化され、順不同で命令を実行し、サイクルごとに 3 ~ 4 個の命令を実行できます。そのため、シングルスレッドのプログラムであっても、コンパイラと CPU が、どの命令をインターリーブして並列実行できるかを判断できることが重要です。

于 2009-11-27T19:35:37.300 に答える
0
  1. Erlang は同期呼び出し用のスーパーバイザーと gen_server コールバックを提供するため、メッセージが配信されない場合にそれがわかります: gen_server 呼び出しがタイムアウトを返すか、スーパーバイザーがトリガーされた場合にノード全体がダウンしてアップします。
  2. 通常、プロセスが同じノード上にある場合、メッセージパッシング言語はデータのコピーを最適化するため、オブジェクトが後で両方で使用されるように変更された場合を除いて、ほとんど共有メモリに似ていますが、いずれにしても共有メモリを使用して行うことはできません
  3. 再帰的な末尾呼び出しでプロセス自体に渡すことによってプロセスによって保持される状態がいくつかあります。また、もちろんメッセージを介して渡すことができる状態もあります。私は mnesia をあまり使用しませんが、これはトランザクション データベースであるため、操作を mnesia に渡すと (そして返されると)、処理が完了することがほぼ保証されます。
  4. そのため、ポートまたはドライバーを使用して、そのようなアプリケーションを erlang に簡単に結び付けることができます。最も簡単なのはポートです。パフォーマンスはそれほど高くないと思いますが、UNIXパイプによく似ています...そして、前述のように、VM /コンパイラがメモリコピーを最適化するため、メッセージパッシングは通常、とにかくポインターパッシングになります.
于 2009-11-30T02:28:58.220 に答える
-1

正確を期すために、共有が最善の方法であり、データを可能な限り正規化してください。即時性のために、メッセージを送信して変更を通知しますが、常にポーリングでバックアップします。メッセージはドロップ、重複、並べ替え、遅延が発生します - それらに依存しないでください。

速度が心配な場合は、まずシングルスレッドで実行し、日光を調整してください。次に、複数のコアがあり、作業を分割する方法を知っている場合は、並列処理を使用します。

于 2009-11-27T19:46:06.440 に答える