読者です 読者をやめる 読者になる 読者になる

成らぬは人の為さぬなりけり

エンジニアライフをエンジョイする為のブログ

Scala勉強日誌 - Akka その1

Scala勉強日誌 - Actor - 成らぬは人の為さぬなりけり
大分前にActorの勉強して、続きでAkkaの勉強しようと思ってて、完全に忘れていたので、
再開したいと思います。
(仕事で必要になって、勉強したので、メモしているだけ、、、)

今日のテーマは、、、

  • SBTプロジェクトを作る
  • AkkaのActorを書いてみる
  • ActorからActorを呼び出して、結果を受け取ってみる
  • Routerを使ってみる。

yagince/akka_practice · GitHub

例によって、環境は、、、

  • OS:MacOSX10.8
  • Scala : 2.10.0
  • sbt :0.12.2
  • Akka : 2.1.0

SBTプロジェクトを作る

まずは、プロジェクトを作ります。
今回は、全部ビルド定義ファイルは全部Scalaで書きたかったので、
こんな感じで作成
project/Build.scala

import sbt._
import Keys._

object BuildSettings {
  val buildOrganization = "yagince"
  val buildVersion      = "0.0.1"
  val buildScalaVersion = "2.10.0"

  val buildSettings = Defaults.defaultSettings ++ Seq (
    organization := buildOrganization,
    version      := buildVersion,
    scalaVersion := buildScalaVersion
  )
}

object Resolvers {
  val typeSafe = "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
  val otherResolvers = Seq(typeSafe)
}

object Dependencies {
  val akkaCore = "com.typesafe.akka" %% "akka-actor" % "2.1.0"
}

object AkkaPracticeBuild extends Build {
  import Resolvers._
  import Dependencies._
  import BuildSettings._

  val dependencies = Seq (
    akkaCore
  )
  
  val project = Project (
    "akka-practice",
    file("."),
    settings =
      buildSettings ++ Seq (
        resolvers := otherResolvers,
        libraryDependencies ++= dependencies
      )
  )
}

project/build.properties

sbt.version=0.12.2

AkkaのActorを書いてみる

では、早速書いてみます。

src/main/scala/akka/sample/AkkaExample01.scala

package akka.sample

import actor.PrintActor
import akka.actor.{Props, ActorSystem}

object AkkaExample01 extends App {
  val system = ActorSystem("sample")
  val actor = system.actorOf(Props[PrintActor], "hoge")

  actor ! "HelloWorld!"

  system.shutdown
}
package akka.sample

import actor.PrintActor
import akka.actor.{Props, ActorSystem}

object AkkaExample01 extends App {
  val system = ActorSystem("sample")
  val actor = system.actorOf(Props[PrintActor], "hoge")

  actor ! "HelloWorld!"

  system.shutdown
}

src/main/scala/akka/sample/actor/PrintActor.scala

package akka.sample.actor

import akka.actor.Actor

class PrintActor extends Actor {
  def receive = {
    case x => println(x)
  }
}

実行結果

> run-main akka.sample.AkkaExample01
[info] Running akka.sample.AkkaExample01 
HelloWorld!
[success] Total time: 0 s, completed 2013/02/13 22:16:22

単純に渡したオブジェクトを出力するだけのアクターです。
これだけ見ても、scala標準Actorより記述量が少ないですね。
そして、シンプル!
素晴らしい。

ActorからActorを呼んで結果を受け取ってみる

Scala標準Actorの同期メソッドみたいのあるのかな??
無さそう???と思っていたら、
こんな風にするのが普通なのかな???
というわけで書いてみます。

package akka.sample

import akka.actor.{ActorSystem, Actor, Props}
import akka.routing.RoundRobinRouter

object AkkaExample02 extends App {
  val system = ActorSystem("sample")
  val actor = system.actorOf(Props[Master])

  actor ! 100

  Thread.sleep(500)
  system.shutdown
}

class Master extends Actor {
  val actor = context.actorOf(Props[DoubleActor])

  def receive = {
    case i:Int => actor ! i
    case Doubled(x) => println("received : %d".format(x))
  }
}

class DoubleActor extends Actor {
  def receive = {
    case i:Int => sender ! Doubled(i*2)
  }
}

case class Doubled(i:Int)

senderへ結果を返して、呼び出し側のreceiveへメッセージパッシングする感じですかね?
確かに、これはシンプルで綺麗だ。
よくよく考えると、同期メソッドって必要ないんじゃなかろうか、、、

Routerを使ってみる

AkkaにはRouterという機能があるようです。
Actorのインスタンスを管理して、
Routerにメッセージ送信すると、
Actorへよしなにバランシングしながらメッセージを横流ししてくれるような感じでしょうか?
書いてみます。

package akka.sample

import actor.{Doubled, DoubleActor}
import akka.actor.{ActorSystem, Actor, Props}
import akka.routing.RoundRobinRouter

object AkkaExample02 extends App {
  val system = ActorSystem("sample")
  val actor = system.actorOf(Props[Master])

  (0 to 10).foreach(actor ! _)

  Thread.sleep(100)
  system.shutdown
}

class Master extends Actor {
  val router = context.actorOf(Props[DoubleActor].withRouter(RoundRobinRouter(2)))

  def receive = {
    case i:Int => router ! i
    case Doubled(x) => println("received : %d".format(x))
  }
}
> run-main akka.sample.AkkaExample02
[info] Running akka.sample.AkkaExample02 
received : 0
received : 2
received : 6
received : 10
received : 4
received : 14
received : 8
received : 18
received : 12
received : 16
received : 20
[success] Total time: 0 s, completed 2013/02/13 22:27:41

一個前の例のMasterクラスを書き換えて、
DoubleActorをRouterで管理するようにしてみました。
Routerの種類は

  • akka.routing.RoundRobinRouter
  • akka.routing.RandomRouter
  • akka.routing.SmallestMailboxRouter
  • akka.routing.BroadcastRouter
  • akka.routing.ScatterGatherFirstCompletedRouter
  • akka.routing.ConsistentHashingRouter

Routing (Scala) — Akka Documentation
これだけあるようです。
それぞれの違いは、また次回ということで、、、

さて、今日はここまでにします。