110

最初に言っておきますが、私は Java の経験が豊富ですが、関数型言語に興味を持ち始めたのはつい最近のことです。最近、私は Scala に注目し始めました。これは非常に優れた言語のようです。

しかし、プログラミング in Scalaで Scala の Actor フレームワークについて読んでいて、理解できないことが 1 つあります。章 30.4reactでは、代わりにreceive使用するとスレッドの再利用が可能になると述べられています。これは、JVM ではスレッドが高価であるため、パフォーマンスに適しています。

reactこれは、の代わりに呼び出すことを覚えている限り、receive好きなだけアクタを開始できるということですか? Scala を発見する前は、私は Erlang をいじっていました。Erlang のプログラミングの著者は、200,000 を超えるプロセスを苦労せずに生成したことを自慢しています。Javaスレッドでそれを行うのは嫌いです。Erlang (および Java) と比較して、Scala ではどのような制限が見られますか?

また、このスレッドの再利用は Scala でどのように機能しますか? 簡単にするために、スレッドが 1 つしかないと仮定しましょう。私が開始したすべてのアクターは、このスレッドで順番に実行されますか? それとも何らかのタスク切り替えが行われますか? たとえば、互いにメッセージをピンポンする 2 つのアクターを開始した場合、それらが同じスレッドで開始された場合、デッドロックの危険がありますか?

Programming in Scalaによると、使用するアクターを記述することreactは、 を使用する場合よりも困難ですreceivereact返されないので、これはもっともらしく聞こえます。ただし、この本は、 をreact使用してループ内に配置する方法を示していますActor.loop。その結果、あなたは得る

loop {
    react {
        ...
    }
}

これは、私にはかなり似ているようです

while (true) {
    receive {
        ...
    }
}

これは本書の前半で使用されています。それでも、この本には、「実際には、プログラムには少なくとも数個receiveの が必要になる」と書かれています。それで、私はここで何が欠けていますか?戻る以外にできること、できないreceiveことは何ですか?reactそして、なぜ私は気にしますか?

最後に、私が理解していないことの核心に来ます.本は、どのように使用reactするとコールスタックを破棄してスレッドを再利用できるようになるかについて言及し続けています。それはどのように機能しますか?コールスタックを破棄する必要があるのはなぜですか? また、関数が例外をスローして終了する場合 ( react) にコール スタックを破棄できるのに、( ) を返すことで関数が終了する場合に破棄できないのはなぜreceiveですか?

Programming in Scalaは、ここでの重要な問題のいくつかをごまかしているように感じますが、それ以外は本当に優れた本なので、これは残念です。

4

5 に答える 5

78

まず、待機中の各アクターreceiveがスレッドを占有しています。何も受信しない場合、そのスレッドは何もしません。アクターreactは、何かを受け取るまでスレッドを占有しません。何かを受け取ると、スレッドがそれに割り当てられ、その中で初期化されます。

ここで、初期化部分が重要です。受信スレッドは何かを返すと予想されますが、反応スレッドはそうではありません。したがって、最後の最後にある以前のスタック状態reactは、完全に破棄される可能性があり、破棄されます。スタック状態を保存または復元する必要がないため、スレッドの開始が速くなります。

さまざまなパフォーマンス上の理由があり、そのいずれかが必要になる場合があります。ご存知のように、Java でスレッドが多すぎるのは得策ではありません。一方、アクターをスレッドにアタッチする前にアクターをアタッチする必要があるため、メッセージよりもメッセージのreact方が高速です。そのため、多くのメッセージを受信するがほとんど処理を行わないアクターがいる場合、追加の遅延により目的に対して遅すぎる可能性があります。receivereactreact

于 2009-08-09T16:43:31.497 に答える
21

答えは「はい」です。アクターがコード内の何もブロックしておらず、 を使用している場合、単一のスレッド内で「並行」reactプログラムを実行できます(システム プロパティを設定して確認してください)。actors.maxPoolSize

コール スタックを破棄する必要があるより明白な理由の 1 つは、そうしないとloopメソッドがStackOverflowError. そのままでは、フレームワークはかなり巧妙に areactをスローして終了しSuspendActorExceptionます。これは、ループ コードによってキャッチされ、メソッドreactを介して再度実行されます。andThen

mkBodyのメソッドを見てActor、次にseqメソッドを見て、ループ自体がどのように再スケジュールされるかを確認してください。

于 2009-08-11T06:25:06.227 に答える
20

「スタックを破棄する」というこれらのステートメントは、私もしばらく混乱させましたが、今では理解できたと思います。これが私の理解です。「受信」の場合、(モニターで object.wait() を使用して) メッセージをブロックする専用のスレッドがあり、これは完全なスレッド スタックが利用可能であり、受信時に「待機」の時点から続行する準備ができていることを意味します。メッセージ。たとえば、次のコードがある場合

  def a = 10;
  while (! done)  {
     receive {
        case msg =>  println("MESSAGE RECEIVED: " + msg)
     }
     println("after receive and printing a " + a)
  }

スレッドは、メッセージが受信されるまで受信呼び出しで待機し、スレッドがブロックされる前にスタックフレームにある「10」の値を使用して、「受信して10を印刷した後」のメッセージを続行して印刷します。

反応の場合、そのような専用スレッドはありません。反応メソッドのメソッド本体全体がクロージャーとしてキャプチャされ、メッセージを受信する対応するアクターの任意のスレッドによって実行されます。これは、クロージャーのみとしてキャプチャできるステートメントのみが実行されることを意味し、そこで「Nothing」の戻り値の型が機能します。次のコードを検討してください

  def a = 10;
  while (! done)  {
     react {
        case msg =>  println("MESSAGE RECEIVED: " + msg)
     }
     println("after react and printing a " + a) 
  }

反応が void の戻り値の型を持っている場合、「反応」呼び出しの後にステートメントを持つことは合法であることを意味します (例では、「反応して 10 を出力した後」というメッセージを出力する println ステートメント)。 「react」メソッドの本体のみがキャプチャされ、後で(メッセージの到着時に)実行するためにシーケンスされるため、実行されることはありません。react のコントラクトの戻り値の型は「Nothing」であるため、react の後にステートメントを含めることはできず、スタックを維持する理由がありません。上記の例では、反応呼び出しの後のステートメントはまったく実行されないため、変数「a」を維持する必要はありません。反応の本体で必要なすべての変数はすでにクロージャーとしてキャプチャされているため、問題なく実行できることに注意してください。

Java アクター フレームワークのKilimは、メッセージを受け取る反応でアンロールされるスタックを保存することで、実際にスタック メンテナンスを行います。

于 2010-06-07T03:15:49.117 に答える
8

ここに置くだけです:

制御の反転を伴わないイベントベースのプログラミング

これらの論文は、Actor の scala api からリンクされており、Actor 実装の理論的フレームワークを提供します。これには、react が返されない理由が含まれます。

于 2010-06-15T14:47:55.503 に答える
0

私は scala /akka で主要な作業を行ったことはありませんが、アクターのスケジュール方法に非常に大きな違いがあることは理解しています。Akka は、アクターのタイム スライス実行である単なるスマート スレッドプールです...各タイム スライスは、アクターによる 1 つのメッセージ実行であり、Erlang とは異なり、命令ごとに実行される可能性があります?!

これは、現在のスレッドがスケジューリングのために他のアクターを検討することを示唆しているため、react の方が優れていると私は考えています。

于 2014-03-11T18:53:27.790 に答える