28

私は Akka と Scala を約 1 か月使用していますが、明示的なインターフェイスをメッセージに置き換えるのは少し面倒です。次の単純な Akka アクターを考えてみましょう。

case class DoMyHomework()
class Parent extends Actor {
  def receive = {
    case d: DoMyHomework => // do nothing
  }
}

このアクターに次のような DoMyHomework メッセージを送信するアクターまたは非アクター コード:

ActorRef parent = ...
parent.ask(DoMyHomework)

結果がどうなるかわかりません。答えの種類は何ですか?私は答えを得ることはありますか?例外を認めることはできますか? 等々。

修正はケースクラスを文書化することのようです...しかし、他のアクターも同じケースクラスを受け取ったらどうなるでしょうか。次に、そのメッセージを受信するためのドキュメントは、アクター自体にある必要があります。

これを少しきれいにするために、次のことを考えました。

trait SomeoneSmarter {
  def wouldYouDoMyHomework: Future[Boolean] 
}
class Parent extends Actor with SomeoneSmarter {
  case class DoMyHomework()
  def wouldYouDoMyHomework = {
    (self ? DoMyHomework()).mapTo(Boolean)
  }
  def receive = {
    case d: DoMyHomework =>
      // TODO: If I'm busy schedule a false "No way" reply for a few seconds from now.
      // Just to keep their hopes up for a while. Otherwise, say sure right away.
  }
}

それで、私はこれについて同僚とおしゃべりをしましたが、反応の 1 つは「俳優モデルに忠実ではない」というものでした。

まず、アクターを長年使用している方からのアドバイスをいただければ幸いです。すべてのメッセージが扱いにくくなりますか? インターフェイスの背後にメッセージの受け渡しを隠すことになりますか?

私が提案しているアクターには、アクター間でメッセージを送信したり、イベント ストリームをサブスクライブしたり、Akka に期待されるすべての機能がまだあります。また、インターフェースは、何と話しているかを知るための定評のある方法を提供します。また、IDE などでコーディングするときにも役立ちます。また、なぜアクターのユーザーはそれがアクターであることを知る必要があるのでしょうか?

私が得たもう 1 つの反応は、「TypedActor が必要なようです」というものでした。しかし、 TypedActor について読んだ後、私は確信が持てません。確かに TypedActor は、これらの内部メッセージを作成する手間を省きます。しかし、少なくとも http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.htmlのコード サンプルからは、TypedActor はブロックの周りのプロキシとしてのみ機能するように意図されているという印象を受けます。カプセル化するか、スレッドセーフにするか、単に現在のスレッドから直接呼び出したくないコードの。コーディングするのは、実装とインターフェースだけです。アクター自体 (プロキシ) を台無しにしないでください。たとえば、実装で定期的な作業を実行したり、イベント ストリームにサブスクライブしたり、インターフェイスに関係のないことをしたりしたい場合などです。

私はhttp://letitcrash.com/post/19074284309/when-to-use-typedactorsも読んだことがありますが、その例がよりわかりやすいとは思いませんでした。私はおそらく TypedActor を理解していないだけです (まだ Actor を本当に理解しているとは言えません)。

助けてくれてありがとう。

ピノ

4

3 に答える 3

11

アクターのカプセル化

最初に、私が非常に重要だと思う点を 1 つだけ答えさせてください。あなたは言う:

また、なぜアクターのユーザーはそれがアクターであることを知る必要があるのでしょうか (それがアクターでもあり、アクターと非常に密接に結び付いている場合を除きます)。

アクターは、従来の OO とは根本的に異なるプログラミング パラダイムです。主な違いは、すべてが非同期であるため、実際の「戻り値」が存在しないことです。これは、それがアクターであるという事実を隠すことは通常悪い考えであることを意味します。例外については、私の TypedActors ブログ投稿を参照してください。アクターの最も優れた点はActorRef、オブジェクト指向言語の弱いカプセル化とは対照的に、完全にカプセル化されている (Akka の背後にある) ことです。それを最大限に活用するには、可能な限り s を公開しActorRefます。これにより、クライアント コードが最も適切な方法でそれらを使用する機会が与えられます (コンテキストを使用するtellask、コンテキストに依存する可能性があります)。

メッセージの構造化

アクターを作成するときは、インターフェイス コントラクトの説明を含め、このアクターに関するすべてを 1 か所に配置する必要があります。次のようになります。

object Parent {
  /**
   * Send this message to make your parent do your homework … yeah, right ;-)
   */
  case object DoHomework
}

/**
 * This actor will do your homework if asked to.
 * 
 * ==Actor Contract==
 * 
 * ===Inbound Messages===
 *  - '''DoHomework''' will ask to do the homework
 * 
 * ===Outbound Messages===
 *  - '''HomeworkResult''' is sent as reply to the '''DoHomework''' request
 * 
 * ===Failure Modes===
 *  - '''BusinessTripException''' if the parent was not home
 *  - '''GrumpyException''' if the parent thinks you should do your own homework
 */
class Parent extends Actor {
  …
}

TypedActor との違い

通常の型指定されていないアクターを使用すると、動作を動的に変更したり、タイムアウトで保護された「同期」呼び出しのケージに自分自身を入れないようにするなど、アクター モデルの全機能を利用できます (要するに、TypedActors は次の場合に最も役立ちます)。舞台裏でアクターを使用して従来の同期インターフェースを実装します)。メッセージ型の IDE サポートが良いことに同意しますが、それはツールの問題です (魔法を追加することについて ScalaIDE チームと話し合っていますが、それが優先されるまで待つ必要があります)。アクターに関するすべてのプロパティを 1 か所で定義することが重要です。

于 2012-09-30T21:10:39.740 に答える
8

免責事項: 私は Akka/Actors の専門家ではありません。私は約 18 か月間 Actors と Akka を使用してきましたが、特に Akka を使用しない場合は特に、特定の概念に頭を悩ませようとしています。

Akka フューチャの戻り値の型を知りたいという特定の狭いケースでは、はい、TypedActor を使用する必要があります。TypedActors を使用したことが数回ありましたが、それらは Actor システムの外にあるモジュールに API を提供するために使用されていました。つまり、私は Akka 上にシステムを構築しました。このシステムは、ほとんどの作業を Akka ネットワーク内で行いましたが、Akka ネットワークが提供する機能へのアクセスを必要とする Akka ネットワークの外部に 1 つまたは 2 つのモジュールがありました。最も注目すべきは、Akka ネットワークを呼び出し、クライアントに応答する前に Akka ネットワークから返された値に対していくつかの作業を行う Scalatra フロントエンドでした。ただし、TypedActor は実際には、Akka ネットワークのフロントエンドに過ぎませんでした。別の懸念事項の分離として、TypedActor を外部 (Akka ネットワークの外部) モジュールへの API フロントエンドとして使用することを検討します。

一般に、戻り値の型のビューを強制しようとして「あなたはアクター モデルに忠実ではない」と言っている人たちに同意します。最も純粋な形で、そして私が最も成功した方法であるアクター モデルは、ファイア アンド フォーゲット セマンティクスを使用して実装されます。メッセージは扱いにくくならず、多くの場合、コードを整理して作業境界を定義するのに役立ちました。それらを独自のパッケージに入れるのに役立ちます。

あなたが説明した機能を実装するとしたら、次のようになります。

trait SomeoneSmarter {

  def wouldYouDoMyHomework : Boolean 

}

class Response()
case class NoWay() extends Response
case class Sure() extends Response

class ActorNetworkFrontEnd extends Actor {

  def receive = {
    case d: DoMyHomework =>
      busy match {
        case true => sender ! NoWay()
        case false => sender ! Sure()
      }
  }
}

case class SomeoneSmarter(actorNetworkFrontEnd:ActorRef) extends SomeoneSmarter {

  def wouldYouDoMyHomework : Boolean = {
    val future = actorNetworkFrontEnd ? DoMyHomework()
    val response = Await.result(future, timeout.duration).asInstanceOf[Response]
    response match {
      case NoWay() => false
      case Sure() => true
    }
  }

}

私が wouldYouDoMyHomework を書いた方法を覚えておいてください。答えを待っている間はブロックされます。ただし、これを非同期で行う賢い方法があります。詳細については、 http://doc.akka.io/docs/akka/2.0.3/scala/futures.htmlを参照してください。

また、メッセージが Akka ネットワーク内に入ると、クールなスケーリングとリモーティングのすべてを行うことができ、TypedActor API のユーザーが知る必要がないことに注意してください。

これを行うと、大規模なプロジェクトでは複雑さが増しますが、API を外部モジュールに提供する責任を分離し、その責任を別のパッケージに移すことさえ考えれば、管理は非常に簡単です。

良い質問。経験豊富な Akka 開発者からの回答を聞くのが待ちきれません。

于 2012-09-21T13:01:53.333 に答える
1

計算のアクター モデルは、オブジェクト指向プログラミングと非常によく似ています。OO は、コントロールの間接的な転送に関するものです。メソッドを呼び出す (メッセージを送信する) と、メッセージを制御できなくなります。もちろん、静的プログラミング言語は、すべての型チェックの良さで少しは役に立ちますが、それ以外は、メッセージがどうなるかわかりません。地獄、おそらくメソッドは決して返されませんが、戻り値の型は明らかに返されると言っています(スローされた例外、ライブロック、名前を付けます...)!Java やさらに優れた Scala に慣れていた場合、静的型付けをあきらめるのはうんざりですが、何のメリットも得られないわけではありません。動的型付けにより、疎結合が実現します。たとえば、テスト用のモック アクターを導入するためだけに追加のインターフェイスを作成する必要はありません。ActorRef必要な唯一の API です。

于 2012-09-21T15:57:46.173 に答える