ExampleChap3

第 3 章 アクターとメッセージによるプログラミング

この章では、ある応用分野の例を見てゆきます。この分野は Scala がとてもよく似合っています。電子オークションサービスを実装する仕事を考えてみて下さい。Erlang 風のアクタープロセスモデルを使ってオークション参加者の実装をしましょう。アクターとはメッセージを受信するオブジェクトです。各アクターはメッセージ受信用の「メールボックス」を持ち、それはキューとして表現されます。メールボックス中のメッセージを順番に処理することも、特定のパターンにマッチするメッセージを検索することもできます。

取引される商品ごとに一つの競売人アクターがあり、そのアクターが、商品についての情報公開、クライアントからの申し込み受付け、取引終了時の売り手および落札者への通知します。ここでは簡単な実装の概要を示します。

最初のステップとして、オークションでやり取りされるメッセージを定義します。クライアントからオークションサービスへのメッセージである AuctionMessage と、サービスからクライアントへの返答である AuctionReply の、2つの抽象基底クラス(abstract base class)があります。両基底クラスには複数のケース(case)があり、図 3.1 で定義されています。

---
import scala.actors.Actor 

abstract class AuctionMessage 
case class Offer(bid: Int, client: Actor) extends AuctionMessage 
case class Inquire(client: Actor)         extends AuctionMessage 

abstract class AuctionReply 
case class Status(asked: Int, expire: Date) extends AuctionReply 
case object BestOffer                       extends AuctionReply 
case class BeatenOffer(maxBid: Int)         extends AuctionReply 
case class AuctionConcluded(seller: Actor, client: Actor) 
                                            extends AuctionReply 
case object AuctionFailed                   extends AuctionReply 
case object AuctionOver                     extends AuctionReply 
  --- Listing 3.1: オークションサービスのメッセージクラス ---

各基底クラスごとに、クラス内の特定のメッセージ形式を定義する ケースクラス (case class)が複数あります。それらのメッセージが、小さな XML 文書に最終的にうまく対応できればよいのですが・・・。ここでは自動化ツールが存在すると仮定して、 XML 文書と、先のように定義された内部データ構造とを変換するとしましょう。

図 3.2 で示す Scala 実装、Auction クラスは、ある商品のオークションを調整する競売人アクターのためのものです。このクラスのオブジェクトは、次を指定して生成されます。

  • オークション終了時に通知する必要のある売り手アクター
  • 最低オークション価格
  • オークションの終了予定時刻

アクターの振る舞いは act メソッドで定義されています。このメソッドでは 、TIMEOUT メッセージによってオークション終了が通知されるまで (receiveWithin を用いて) メッセージを選択し、それに対応することを繰り返します。最終的に停止する前まで、定数 timeToShutdown で定められた期間はアクティブであり続け、さらなる申し出に対してはオークションを締切った旨を返答します。

このプログラムで使われている構文について、さらにいくつか解説します。

  • クラス Actor の receiveWithin メソッドはパラメータとして、期間 (ミリ秒単位) とメールボックスのメッセージを処理する関数をとります。関数は一連のケースとして与えられ、各ケースはパターンと、そのパターンに対応したメッセージを処理するアクションを指定します。receiveWithin メソッドは、メールボックスからパターンにマッチする最初のメッセージを選び、対応するアクションを適用します。
  • receiveWithin の最後のケースは TIMEOUT パターンで守られています。もし有効時間内にメッセージを受け取らなければ、receiveWithin メソッドの引数として渡された期間経過後に、このパターンが起動されます。TIMEOUT は特別なメッセージで、Actor の実装そのものによって起動されます。
  • 応答メッセージを送信する構文として、destnation ! SomeMessage (宛先 ! メッセージ) を用います。ここで ! は、アクターとメッセージを引数とする二項演算子のように使われています。これは Scala では、メソッド呼び出し destination.!(SomeMessage)、すなわち、メッセージをパラメータとした destination アクターの ! メソッド呼び出しと同じです。
---
class Auction(seller: Actor, minBid: Int, closing: Date) extends Actor { 
  val timeToShutdown = 36000000 // msec 
  val bidIncrement = 10 
  def act() { 
    var maxBid = minBid - bidIncrement 
    var maxBidder: Actor = null 
    var running = true 
    while (running) { 
      receiveWithin ((closing.getTime() - new Date().getTime())) { 
        case Offer(bid, client) => 
          if (bid >= maxBid + bidIncrement) { 
            if (maxBid >= minBid) maxBidder ! BeatenOffer(bid) 
            maxBid = bid; maxBidder = client; client ! BestOffer 
          } else { 
            client ! BeatenOffer(maxBid) 
          } 
        case Inquire(client) => 
          client ! Status(maxBid, closing) 
        case TIMEOUT => 
          if (maxBid >= minBid) { 
            val reply = AuctionConcluded(seller, maxBidder) 
            maxBidder ! reply; seller ! reply 
          } else { 
            seller ! AuctionFailed 
          } 
          receiveWithin(timeToShutdown) { 
            case Offer(_, client) => client ! AuctionOver 
            case TIMEOUT => running = false 
          } 
        } 
      } 
    } 
  }
       --- Listing 3.2: オークションサービスの実装 ---

ここまでの話は、Scala における分散プログラミングの雰囲気を示したものです。Scala にはアクタープロセス、メッセージ送受信、タイムアウトのあるプログラミングなどをサポートする豊富な言語構文があるように見えたかもしれません。実際は全く逆です。これまでに議論した言語構文はすべてクラス Actor のライブラリ内でメソッドとして提供されています。そのクラス自身が Scala で実装されており、基礎となるホスト言語 (つまり Java や .NET) のスレッドモデルに基づいています。ここで使った Actor クラスの特徴すべての実装については、17.11 節で述べられています。

ライブラリベースのアプローチの利点は、相対的な、コア言語の簡潔さとライブラリ設計者への柔軟性にあります。コア言語では高レベルなプロセス間通信の詳細を規定する必要がないので、簡潔、一般性を保つことができます。メールボックス内メッセージのこのモデルは単なるライブラリモジュールなので、あるアプリケーションが異なるモデルを必要とする場合は、自由に変更できます。しかしながら、このアプローチはコア言語に対して、必要とされる言語の抽象化を使いやすい形で提供できるような十分な表現力を要求します。Scala はこのことを念頭においてデザインされました。Scala デザインの大きな目標の一つは、ライブラリモジュールによって実装される、ドメイン特化言語(DSL)ための使いやすいホスト言語たりうる、柔軟性にあります。たとえば先に示したアクター間通信の構文は、そのようなドメイン特化言語とみることができ、無意識に Scala コアを拡張しています。


「actor process model」が不明です。Erlang-styleならば「Actor model」では? 「case object」の説明は無し?

ーーーーー修正案 by ryugate

※ 修正案を取り入れました。

TIMEOUT は特別なメッセージで、Actor の実装そのものにトリガーされます。 →TIMEOUT は特別なメッセージで、Actor の実装そのものによってトリガーされます。

  • ご指摘どうもありがとうございます>ryugateさん。 -- tmiya (2008-05-14 06:59:29)
  • 「might well」は「~良いのですが」ではなく「~でしょう」ではないでしょうか? -- kariya_mitsuru (2012-09-19 01:00:17)
    名前:
    コメント:

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2012年09月19日 12:41
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。