6

(Scala) アクターは実際には 2 つの操作を同時に実行することは決してないと聞いています。act メソッドでの長い操作がブロックの問題を引き起こす可能性があることはわかっています。また、メッセージ キューへのアクセスを何らかの方法で同期する必要があると思いますが、...

提案されたのは、内部カウンターをインクリメントするように指示するメッセージを受け取ったアクターは、スレッドセーフな方法でカウンターをインクリメントするということです。2 つの更新メッセージが同時に処理されないため、2 つのメッセージが同時にカウンターを更新しようとすることはありません。

アクターのカウンター属性は「共有状態」のように聞こえます。

そのような操作が完全にスレッドセーフであるというのは本当ですか? もしそうなら、攻撃者はどのようにして効率的な方法で複数のコア マシンを利用するのでしょうか? アクターはどのようにマルチスレッド化されていますか?

そうでない場合、同期/揮発変数を必要とせずにスレッドセーフな方法でメッセージをカウントする適切な慣用的な方法は何ですか?

4

3 に答える 3

8

アクターモデルは、可変状態を外界から分離するために使用できます。可変状態(たとえば、複数の並行プロセスに割り当てられたIDのグローバルレジストリ)がある場合、その可変状態をアクター内にラップし、クライアントにメッセージパッシングを介してアクターと通信させることができます。そうすれば、アクターだけが可変状態に直接アクセスし、あなたが言うように、クライアントメッセージは1つずつ読み取られて処理されるようにキューに入れられます。メッセージが不変であることが重要です。

キューがいっぱいになるのを防ぐために、メッセージ処理(、、など)をできるだけ短くすることが重要reactですreceive。実行時間の長いタスクは、他のアクターに渡す必要があります。

1.  Actor A receives a message M from sender S
2.  A spawns a new actor C
3.  A sends (S, f(M)) to C
4.  In parallel:
4a. A starts processing the next message.
4b. C does the long-running or dangerous (IO) task,
    When finished, sends the result to S,
    and C terminates.

プロセスのいくつかの選択肢:

  • C(S, result)はSに転送するAに送り返します
  • Aはマッピングを保持するActorRef C => (Sender S, Message M) ため、Cが失敗した場合は、新しいアクターでMの処理を再試行できます。

要約すると、アクターは、複数のクライアントがさまざまなスレッドから複数のメッセージを送信できる範囲でマルチスレッド化されており、アクターがこれらすべてのメッセージを連続して処理することが保証されています(ただし、順序付けは、過度ではないさまざまな対象になる可能性があります)厳格な制約)。

アクターのreactコードはさまざまなスレッドで実行される可能性がありますが、単一の特定の時点では、単一の特定のスレッドでのみ実行されることに注意してください(スケジューラーが適切と考えるように、アクターがスレッドからスレッドにジャンプすることを想像できますが、これは技術的な詳細です)。注:アクターはメッセージの処理間のセマンティクスの前に発生することを保証するため、内部状態は同期化を必要としません。

並列処理は、複数のアクターを並列に動作させ、通常はスーパーバイザー階層を形成するか、ワークロードのバランスをとることによって実現されます。

必要なのが並行/非同期計算だけであるが、グローバル状態を持っていないか、取り除くことができない場合は、Futuresの方が構成が簡単で概念が簡単であることに注意してください。

于 2012-09-13T05:50:37.000 に答える
6

「アクター」はマルチスレッド化されていませんが、アクター システムは通常マルチスレッド化されています。各アクターは一度に 1 つのアクションのみを実行しますが、複数のアクターが存在する場合、各アクターはそれぞれのカプセル化された状態で並行して動作できます。カウンター属性は、アクター間で共有されていない場合、変更可能な状態ではありません。

質問がアクター システムの実装に関するものである場合、それはさまざまであり、通常は構成可能です。つまり、デフォルトの Scala アクターは、シングル スレッドまたはスレッド プール上で実行するか、Java ForkJoin タスクを使用して実行するように構成できます。scala.actors のソースは非常に読みやすいので、何が起こっているのかを理解したい場合は、一読することをお勧めします。

于 2012-09-13T04:56:38.877 に答える
2

別のアクターを使用してカウントを行うことができます。アクターがメッセージを受け取ると、(シングルトンの) カウント アクターにメッセージを送信できます。このようにして、複数のワーカー アクターを使用し、メッセージをカウントすることができます。

Akka にはAgents、このコンテキストで役立つ可能性があると呼ばれるものがあります。

val counter = Agent(0)
counter send (_ + 1)

http://doc.akka.io/docs/akka/2.0.2/scala/agents.html

于 2012-09-13T05:12:37.067 に答える