web-dev-qa-db-ja.com

ScalaのアクターはGoのコルーチンに似ていますか?

Goroutinesを使用するGoライブラリを移植したい場合、Scala=は、その受信トレイ/ akkaフレームワークが本質的にコルーチンに似ているため、良い選択でしょうか?

70
loyalflow

いいえ、そうではありません。ゴルーチンは、1978年にTony Hoareによって指定された、連続プロセスの通信の理論に基づいています。アイデアは、互いに独立して動作するが、1つのプロセス/スレッドがデータを置く「チャネル」を共有する2つのプロセスまたはスレッドが存在する可能性があるということです他のプロセス/スレッドが消費します。最も顕著な実装は、GoのチャネルとClojureのcore.async、ただし、現時点では、それらは現在のランタイムに制限されており、同じ物理ボックス上の2つのランタイム間でも配布できません。

CSPは、コード内にデッドロックが存在することを証明するための静的で正式なプロセス代数を含むように進化しました。これは本当に素晴らしい機能ですが、ゴルーチンやcore.async現在サポートしています。その場合、コードを実行する前に、デッドロックが発生する可能性があるかどうかを知ることは非常に良いことです。ただし、CSPは意味のある方法でフォールトトレランスをサポートしていないため、開発者はチャネルの両側で発生する可能性のある障害を処理する方法を把握する必要があり、そのようなロジックはアプリケーション全体に散らばってしまいます。

1973年にCarl Hewittによって指定されたアクターには、独自のメールボックスを持つエンティティが含まれます。本質的に非同期であり、ランタイムとマシンにまたがる位置の透過性を持っています-アクターの参照(Akka)またはPID(Erlang)がある場合、メッセージを送ることができます。これはまた、一部の人々がアクターベースの実装で欠点を見つける場所でもあり、メッセージを送信するために他のアクターへの参照を持たなければならないため、送信者と受信者を直接結合します。 CSPモデルでは、チャネルは共有され、複数のプロデューサーとコンシューマーで共有できます。私の経験では、これはそれほど大きな問題ではありませんでした。私はコードにメッセージの送信方法の実装の詳細が散らばっていないことを意味するプロキシ参照のアイデアが好きです-私はただ1つを送信し、アクターがどこにいてもそれを受信します。そのノードがダウンし、アクターが別の場所に生まれ変わった場合、理論的には透過的です。

アクターには、フォールトトレランスという非常に優れた機能があります。 Erlangで考案されたOTP仕様に従って監督階層にアクターを編成することにより、アプリケーションに障害のドメインを構築できます。値クラス/ DTO /それらを呼び出すものと同じように、障害、その処理方法、および階層のレベルをモデル化できます。これは非常に強力です。CSP内には障害処理機能がほとんどありません。

アクターは同時実行パラダイムでもあり、アクターはその内部で可変状態を持ち、アクターベースのシステムを構築している開発者がアクタをリスナーとして登録するなどして誤って導入しない限り、状態へのマルチスレッドアクセスを保証しますコールバックの場合、またはFutureを介してアクター内で非同期になる場合。

恥知らずのプラグ-Akkaチームの代表であるRoland Kuhnと共に、Reactive Design Patternsと呼ばれる新しい本を執筆しています。グリーンスレッド、CSP、イベントループ、Iteratees、Reactive Extensions、アクター、フューチャーズ/プロミスなど。来月初旬までにManningでMEAPが行われる予定です。

がんばろう!

128
jamie

私のコメントの一部を回答に移動します。長すぎました:D(jamieとtolitiusの投稿を奪わないでください。どちらも非常に有用な回答です)

Akkaのゴルーチンを使用する場合とまったく同じことを実行できるということはあまりありません。 Goチャネルは、多くの場合、同期ポイントとして使用されます。 Akkaで直接再現することはできません。 Akkaでは、同期後処理を別のハンドラーに移動する必要があります(jamieの言葉で「ばらまかれ」:D)。デザインパターンが異なると思います。 chanを使用してゴルーチンを開始し、いくつかの処理を行ってから、<-が終了するのを待ってから先に進むことができます。 Akkaにはaskを使用したこれほど強力ではない形式がありますが、askは実際にはAkkaのIMOではありません。

チャンも入力されますが、メールボックスは入力されません。これは大したIMOであり、Scalaベースのシステムにとってはかなり衝撃的です。型付きメッセージを使用してbecomeを実装するのは難しいことを理解していますが、それはbecomeがScalaに似ていないことを示している可能性があります。私はAkkaについて一般的にそれを言うことができます。多くの場合、Scalaで実行される独自のもののように感じます。ゴルーチンは、Goが存在する主な理由です。

誤解しないでください。私は俳優モデルが大好きで、一般的にAkkaが好きで、仕事をするのが楽しいと思います。また、Goも好きです(Scala beautifulですが、Goは単に役に立つと思いますが、とても便利です) )。

しかし、耐障害性は本当にAkka IMOのポイントです。あなたはそれと並行性を得ることがあります。並行性はゴルーチンの中心です。フォールトトレランスはGoの別のものであり、deferrecoverに委任されます。これらは、かなりのフォールトトレランスを実装するために使用できます。 Akkaのフォールトトレランスは、より形式的で豊富な機能を備えていますが、少し複雑な場合もあります。

いくつかの共通点はあるものの、AkkaはGoのスーパーセットではなく、機能に大きな違いがあります。 AkkaとGoは、問題へのアプローチを奨励する方法がまったく異なります。一方は簡単ですが、もう一方は扱いにくい、非実用的、または少なくとも非慣用的です。そして、それはどんなシステムでも重要な差別化要因です。

したがって、実際の質問に戻してください。GoインターフェイスをScalaまたはAkka(IMOとはまったく異なるもの)にする前に、再考することを強くお勧めします。ターゲット環境が物事を行うことを意味する方法でそれをしていることを確認してください。複雑なGoライブラリのストレートポートは、どちらの環境にも適合しない可能性があります。

8
Rob Napier

これらはすべて素晴らしく徹底的な答えです。しかし、それを見る簡単な方法のために、ここに私の見解があります。ゴルーチンは、アクターの単純な抽象化です。アクターは、ゴルーチンのより具体的なユースケースです。

ゴルーチンをチャネルの横に作成することにより、ゴルーチンを使用してアクターを実装できます。そのGoroutineによってチャネルが「所有」されていると判断することにより、GoroutineのみがそのGoroutineから消費することを意味しています。 Goroutineは、そのチャンネルで受信トレイとメッセージのマッチングループを実行するだけです。その後、単純にチャンネルを「俳優」(ゴルーチン)の「アドレス」として渡すことができます。

しかし、ゴルーチンは抽象化であり、アクターよりも一般的なデザインであるため、ゴルーチンはアクターよりもはるかに多くのタスクとデザインに使用できます。

ただし、トレードオフは、アクターがより具体的なケースであるため、Erlangなどのアクターの実装はそれらをより最適化でき(受信トレイループでのレール再帰)、他の組み込み機能をより簡単に提供できる(マルチプロセスおよびマシンアクター) 。

6
DragonFax

アクターモデルでは、アドレス可能なエンティティはメッセージの受信者であるアクターであると言えますか。 Goチャネルでは、アドレス可能なエンティティはチャネルであり、メッセージが流れるパイプです。

goチャンネルでは、チャンネルにメッセージを送信すると、任意の数の受信者がリッスンでき、そのうちの1人がメッセージを受信します。

アクターでは、メッセージを送信するactor-refを持つ1つのアクターのみがメッセージを受信します。

1
weima