アクターモデル:なぜエルランは特別ですか?それとも、別の言語が必要なのですか?

私はerlangを学ぶことを検討してきました。その結果、俳優のモデルについて読んでいました(大丈夫、スキミング)。

私が理解しているところから、アクターモデルは、単純にメッセージの受け渡しによってのみ互いに​​通信する関数群(erlangの "プロセス"と呼ばれる軽量スレッド内で実行される)の集合です。

これはC ++やその他の言語で実装するのはかなり簡単です。

class BaseActor {
    std::queue messages;
    CriticalSection messagecs;
    BaseMessage* Pop();
public:
    void Push(BaseMessage* message)
    {
        auto scopedlock = messagecs.AquireScopedLock();
        messagecs.push(message);
    }
    virtual void ActorFn() = 0;
    virtual ~BaseActor() {} = 0;
}

それぞれのプロセスは、派生したBaseActorのインスタンスです。アクターは、メッセージの受け渡しを介してのみ互いに​​通信します。 (すなわち、押す)。アクターは、他のアクターがそれを見つけることを可能にする初期化時に中央マップを登録し、それらを介して中央機能を実行させる。

さて、私は、私が行方不明、またはむしろ、ここで一つの重要な問題、すなわち: 降格の欠如は、単一の俳優が過度の時間を不公平に消費する可能性があることを意味する。しかし、クロスプラットフォームのコルーチンは、これをC ++で難しくする主なものですか? (例えば、Windowsにはファイバーがあります。)

私は行方不明の他に何かがありますか、またはモデルは本当に明らかですか?

私は間違いなくここで炎戦を始めようとはしていませんが、これは本質的に同時コードについて幾分理由があるのです。

74
erlangプロセスは、同じマシン上または異なる物理マシン上に存在することができます(実際に実行するコードは多少なりとも同じです)。そのため、例は大幅に単純化されているようです。そして、ホットスワッピングコードはどうでしょうか、C ++はそれを簡単に行うことができますか?あなたのC + +の俳優のメモリサンドボックスですか?
追加された 著者 Kevin,
ところでスカラーにはアクターモデルもあります(Akka)ので、アクターは確かにエルランに限られていません。しかし、私はあなたが思うように(少なくとも大きな制限がない限り)C ++で行うのは簡単だとは思わない。
追加された 著者 Kevin,
一回限りの実装コストではありませんか?真剣に考えても、サンドボックス環境の欠如は深刻な欠点であると思います。なぜなら、1人の俳優がシステム全体をダウンさせる可能性があるからです。
追加された 著者 Kevin,
私はすべての答えを知らないが、あなたはjavaのアクターであるAkkaプロジェクトについて読むことから始めるかもしれない。それはあなたが簡単で難しいものを指し示すかもしれないので、エルランの俳優に比べていくつかの制限があります。
追加された 著者 Kevin,
プログラミング言語の目的は、アイデアや仕様の表現を助けることです。アーランではアクターモデルが暗黙されていますので、どちらの言語でもモデルでアイデアを表現できますが、Erlangではボイラープレートがあなたのために行われるので、もっと良いでしょう。
追加された 著者 GManNickG,
@セス: "それは一度考えて、私は"ええええええええええええええええええええええええ。私は初めて何かを完璧に書く人は知らない。このコードを改善する方法は何でも考えられません。または既存のアーラン実装ですか?
追加された 著者 GManNickG,
追加された 著者 oluies,
一旦ボイラープレートが完成すれば(それは一度考えると思う、私は思うだろう)何が利点なのだろう?
追加された 著者 Seth Carnegie,
@GMan私はあなたが一度だけ書くことを意味しなかった、私はあなたがすべてのプログラムのためにそれを書く必要がないということを意味した。
追加された 著者 Seth Carnegie,
C ++で安全で信頼性が高く、並行して保守可能なコードを実装することができれば、すぐに作業を進めることができます。しかし、このスニペットからトンが欠落しています。 erlangのコアは信頼性です。プロセスがそのタスクを実行できない場合、プロセスは失敗し、その失敗メッセージはシステムを介して伝播され、複雑な依存グラフがさまざまなタイプの停止(またはバグ)で再構成されます。 できますがすることはできますが、なぜ誰もしないことを尋ねているはずです。それが新しい言語につながっています。
追加された 著者 Dustin,
私はSOゲスタポによって閉鎖されていないことに驚いています。しかし、俳優のモデリングはC ++やCでも可能であるということは間違いありません。明らかに、多くの努力が必要であり、構文的に乱雑になる可能性があります。
追加された 著者 user922475,
@ダスティン:それはまさに私が求めていることです。 Re:私は何が欠けている。スニペットは分かりやすく書き込まれていたので、それは「完全」ではないことは明らかです。
追加された 著者 Jonathan Winks,
@ケビン:十分に真実。私が作ろうとしていたポイントは、実装が比較的少額で済んだら、同じ言語を使い続けることです。つまり、別の言語の特異性を学ぶ必要はなく、そのパフォーマンスに抱かれているわけでもありません。言語を理解することとパフォーマンスは、よく設計された分散システムにとって重要です。コードの最も難しい部分を書くために、短期間でも長期的にもコストがかかるなら、なぜ言語を切り替えてコードを書くのですか?私の質問は、アクターモデルは本当に簡単なのですか?そうでなければ、私は何が欠けていますか?
追加された 著者 Jonathan Winks,
@ケビン:同じマシン/別のマシン:不可能ではない。しかし、コードスニペットよりも難しい。しかしもう一度:1回の実装コスト。ホットスワップコード:アクターモデルとは無関係であり、したがって、この質問の範囲外です。メモリサンドボックス:いいえ、これを(C ++で)行うことはおそらく不可能であり、それを要件としても見ません。 C + +はナニーの言語ではありません。
追加された 著者 Jonathan Winks,
@セスカーネギー:それは確かに私の質問の要点です。
追加された 著者 Jonathan Winks,

6 答え

C ++コードは、Erlangがそのアクターモデルの一部としてもたらすすべてのものである公平性、分離性、障害検出または分布を処理しません。

  • 他の俳優を飢えさせる俳優はいない(公正さ)
  • 1つのアクタがクラッシュした場合、そのアクタ(アイソレーション)にのみ影響するはずです。
  • あるアクタがクラッシュした場合、他のアクタはそのクラッシュを検出して対応する必要があります(障害検出)
  • アクターはネットワーク上で同じマシン(ディストリビューション)にいるかのように通信できる必要があります。

また、ビームSMPエミュレータは、アクターのJITスケジューリングを実行し、アクターをコアに移動させます。コアは現在使用率が最も低いコアに移動し、不要になった場合は特定のコアでスレッドを休止します。

さらに、Erlangで書かれたすべての図書館やツールは、これが世界の仕組みであり、それに応じて設計されていると考えることができます。

これらのことはC ++では不可能ではありませんが、Erlangが主なhwとosの設定のほとんどすべてで動作するという事実を追加すると、ますます難しくなります。

編集:ちょうど Ulf Wiger は、erlangスタイルの並行性がどのようなものかを見ています。

82
追加された
@Karmastanはい、Erlangのプロセスは非常に安価です。/並行性はアプリケーションの構造化の基本的な抽象であるからです。 Erlangを設計したときにアクターのことを聞いたことのない、アクター以外のプロセスをプロセスと呼んでいます。 :-)
追加された 著者 rvirding,
erlang並行性モデルにはプロセス分離エラー処理が含まれています。
追加された 著者 rvirding,
リストされたすべてのプロパティは、オペレーティングシステムによってプロセスに提供されます。 C ++プログラムは、他のプログラムと同様に、それらを簡単に使用することができます。私はErlangの鍵は、その俳優がそれらのプロパティを提供するためのOSプロセスよりもはるかに安いということです。その結果、俳優はより自由に使用することができます。
追加された 著者 Karmastan,

I don't like to quote myself, but from Virding's First Rule of Programming

別の言語で十分に複雑な並行プログラムがあれば、Erlangの半分の非公式に指定された、バグに敏感な、遅い実装が含まれています。

Greenspunに関して。 Joe(Armstrong)も同様のルールを持っています。

問題はアクターを実装することではなく、それほど難しいことではありません。問題は、プロセス、通信、ガーベジコレクション、言語プリミティブ、エラー処理など、すべてを連携させることです。たとえば、OSスレッドを使用するとひどくスケールされるので、自分で処理する必要があります。それは、あなたが1k個のオブジェクトしか持たないOO言語を "売る"ようなもので、作成して使うのは重いです。私たちの視点から見ると、並行処理はアプリケーションを構造化するための基本的な抽象です。

私はここでやめます

29
追加された

これは実際には素晴らしい質問ですが、おそらくまだ説得力のない優れた回答を得ています。

他の素晴らしい答えに色合いと強調を追加するには、フォールトトレランスと稼働時間を達成するために、Erlangを取り除く(C/C ++などの従来の汎用言語と比較して)。

まず、ロックを解除します。ジョー・アームストロングの本では、あなたのプロセスがロックを取得した後すぐにクラッシュすると(メモリの不具合によりプロセスがクラッシュしたり、システムの一部に電力が供給されなかったとします)、この思考実験が行われています。次にプロセスが同じロックを待つとき、システムはただデッドロックしてしまいます。これは、サンプルコードのAquireScopedLock()コールのように、明白なロックになる可能性があります。 malloc()またはfree()を呼び出すときなど、メモリマネージャによって暗黙的にロックが取得される可能性があります。

いずれにしても、プロセスクラッシュによってシステム全体が停止することがなくなりました。フィニ。物語の終わり。あなたのシステムは死んでいる。 C/C ++で使用するすべてのライブラリがmallocを呼び出すことはなく、決してロックを取得しないことを保証できない限り、システムはフォールトトレラントではありません。 Erlangシステムは、負荷がかかっている場合にはプロセスを強制的に終了させることができますが、スループットを維持するには、Erlangプロセスを(単一の実行ポイントで)kill可能にする必要があります。

部分的な回避策があります:ロックの代わりにどこでもリースを使用しますが、使用するすべてのライブラリもこれを行うという保証はありません。そして、正しさについての論理と推論は、本当に素早く毛深くなります。さらに、リースはゆっくりとリカバリされます(タイムアウト後に期限切れになります)。その結果、システム全体が非常に遅くなってしまいます。

次に、Erlangは静的な型指定を取り除きます。これにより、ホットコードスワップと同じコードの2つのバージョンの同時実行が可能になります。つまり、システムを停止することなく、実行時にコードをアップグレードすることができます。これは、9つの9秒間、または32ミリ秒のダウンタイム/年の間、システムがどのように動作するかを示します。彼らは単にその場でアップグレードされます。あなたのC ++機能は、アップグレードするために手動で再リンクする必要があり、同時に2つのバージョンを実行することはサポートされていません。コードのアップグレードにはシステムのダウンタイムが必要となります。一度に複数のバージョンのコードを実行できない大規模なクラスタを使用している場合は、一度にクラスタ全体をダウンする必要があります。ああ。そして通信業界では、耐えられない。

さらにErlangは共有メモリと共有共有ガベージコレクションを取り除きます。各軽量プロセスは、独立してガーベッジ・コレクションされます。これは最初の点を簡単に拡張したものですが、真のフォールトトレランスのためには、依存関係の中でインターロックされていないプロセスが必要であることを強調しています。これは、大きなシステムでは、Javaに比べてGCの一時停止が許容されることを意味します(8GBのGCが完了するまでに30分を一時停止するのではなく、わずかです)。

21
追加された
有効な音ですが、それはC ++の比較であり、C ++は常に責任のある簡単なターゲットです。例えば、Java(またはClojure)でこれを持つことはできませんか? Javaのロックは安全で、実行時にコードをコンパイル/ロードする方法があります(Clojureではこれも非常に簡単です)。
追加された 著者 Sarge Borsch,
まず、lock_guardを使用して、プログラムがクラッシュした場合のロックを解除します。第二に、C ++でホットスワップシステムを実装することができますが、それは苦痛です...並行性の問題は、同期プリミティブ、アトミックであっても、メモリフェンスとバリアを導入し、遅くなることです。あなたが持っているスレッドが多いほど、あなたは遅くなります。 clojureやhaskellとしてのErlangは、mutexやatomicsを使用しないため、開発者は別の方法で問題を解決する必要があります。これは並行性の問題を解決する非常に効率的な方法です
追加された 著者 Asier Gutierrez,

C ++用の実際の俳優ライブラリがあります:

他の言語のいくつかのライブラリのリスト

14
追加された
libcppaは最近C ++ Actor Framework(CAF)に名称変更されました。新しいURLは次のとおりです。 github.com/actor-framework/actor-framework
追加された 著者 mavam,

アクターモデルはかなり少なく、CTPでOTPに類似したものを正しく書くことがどれほど難しいかについて多くのことがあります。また、さまざまなオペレーティングシステムでは、根本的に異なるデバッグとシステムツールが提供されています。アーランのVMといくつかの言語構造は、それらのプロセスが統一された方法で実行することが非常に難しいまったく)いくつかのプラットフォームで使用できます。 (Erlang/OTPは「アクターモデル」という言葉よりも現在の話題に先んじていることを覚えておくことが重要です。したがって、これらの議論はリンゴと蝶を比較しています;素晴らしいアイデアは独立した発明になりがちです。

これは、あなたが確かに別の言語でプログラムの "アクターモデル"スイートを書くことができる間に(私は知っている、私はアーロンを遭遇する前にPython、CとGuileでそれを実現していない、実際にコードがどのように生成され、何が起こっているかを理解することは非常に難しいです。 Erlangは、OSが単純に主要なカーネルのオーバーホールなしにはできないルールを強制します。カーネルのオーバーホールはおそらく全体的には有益ではないでしょう。これらのルールは、プログラマの一般的な制限(本当に必要な場合にはいつも得られます)と、システムがプログラマにとって保証する基本的な約束(あなたが本当に必要な場合に故意に壊れる可能性がある)の両方として現れます。

たとえば、副作用からあなたを守るために、2つのプロセスが状態を共有できないように強制します。これは、すべての関数が、すべてが明確に透明であるという意味で "純粋"でなければならないというわけではありません(明らかにそうではありませんが、ほとんどのErlangの明確な設計目標は、むしろ、2つのプロセスが共有状態または競合に関連する競合条件を絶えず作り出すわけではないということです)。 (これはErlangの文脈で "副作用"が何を意味するのかということであり、ErlangがHaskellやおもちゃの "純粋な"言語と比較してErlangが本当に機能的かどうかを議論する議論の一部を解読する助けとなるかもしれない。)

一方、Erlangランタイムはメッセージの配信を保証します。これは、管理されていないポート、パイプ、共有メモリ、およびOSカーネルだけが管理する共通ファイル(これらのリソースのOSカーネル管理は、Erlangランタイムが提供する)。これはErlangがRPCを保証するものではありません(とにかく、メッセージの受け渡しは RPCではなく RPCでもメソッド呼び出しでもありません)、メッセージが正しく扱われることを保証するものではありません。メッセージを送信しようとしているプロセスが存在しているか、生きているプロセスであることを保証します。あなたの送信がその瞬間に有効である場合にのみ、配送を保証します。

この約束は、モニターとリンクが正確であることを約束するものです。そして、Erlangランタイムは、システムに何が起こっているのか(そしてerl_connectの使い方)を理解すると、Erlangランタイムは「ネットワーククラスタ」という概念全体を溶かしてしまいます。これにより、既に厄介な並行処理のケースを跳ね上げることができます。これは、裸の並行プログラミングに必要な防御技術の沼地に陥るのではなく、成功したケースのコーディングで大きな前進をもたらします。

ですから、Erlang、その言語、既に存在するランタイムとOTPに関する必要な必要がないことは、かなりクリーンな方法で表現されています。 OTPはちょうど従うべき難しい行為です。同じように、私たちは本当にC ++を必要としませんが、生のバイナリ入力Brainfuckに固執して、アセンブラの高水準言語を考慮することもできます。私たちは歩く方法と泳ぐ方法をすべて知っているので、列車や船は必要ありません。

言い換えれば、VMのバイトコードは十分に文書化されており、Erlangランタイムでコンパイルしたり、動作させるための多くの代替言語が登場しています。質問を言語/構文部分(「ムーンルーンが同時性を行うことを理解する必要がありますか?」)とプラットフォーム部分(「OTPは最も成熟した並行処理方法ですか?最も一般的な落とし穴は並行分散環境で見つかるはずですか? ")、答えは(" no "、" yes ")です。

3
追加された

Casablanca is another new kid on the actor model block. A typical asynchronous accept looks like this:

PID replyTo;
NameQuery request;
accept_request().then([=](std::tuple request)
{
   if (std::get<0>(request) == FirstName)
       std::get<1>(request).send("Niklas");
   else
       std::get<1>(request).send("Gustafsson");
}

(個人的には、 CAF が素敵なパターンの後ろのパターンマッチングを隠す上でより良い仕事をすることがわかりますインタフェース。)

2
追加された