時計を壊せ

駆け出しWebプログラマーの雑記

Akka 2.4を雑にためす: その1

※ メモです

Scalaもくもく会に参加した。 Gitterでわいわいしながら自分のペースでもくもくできてよかった。
第1回 Scalaもくもく会@Volare - connpass
第2回 Scalaもくもく会@Volare - connpass

ぼくは、Actorが使ってみたくてScalaでAkkaをためしてみた。 ドキュメント長すぎて読むのに気力と体力が要求されたので、 とりあえずドキュメントを読まずにサンプルコードを書き換えてみるという、 非常にカジュアルな試しかたをした。

まずはbuild.sbtを書く。

lazy val root = (project in file(".")).
  settings(
    name := "tut",
    version := "1.0",
    scalaVersion := "2.11.6",
    libraryDependencies += "com.typesafe.akka" % "akka-actor_2.11" % "2.4-SNAPSHOT",
    libraryDependencies +=  "org.scalaj" %% "scalaj-http" % "1.1.4",
    resolvers += "Akka Snapshot Repository" at "http://repo.akka.io/snapshots/"
  )

雑に1秒遅れてEchoするActorを書く。

import akka.actor.{Actor,ActorSystem,Props}
import akka.pattern.ask
import akka.pattern.gracefulStop
import akka.util.Timeout
import scala.concurrent.Future
import scala.concurrent.Await
import scala.concurrent.duration._

class DelayEchoActor extends Actor {
  def receive = {
    case msg: String =>
      Thread.sleep(1000)
      sender ! msg
  }
}

object HelloWorld {
  def main(args: Array[String]) = {
    var sys = ActorSystem("system")
    val echo = sys.actorOf(Props[DelayEchoActor])

    implicit val timeout = Timeout(10 seconds)

    val futures = scala.collection.mutable.ArrayBuffer.empty[Future[Any]]
    futures += echo ? "あれ?"
    futures += echo ? "文字列が"
    futures += echo ? "遅れて"
    futures += echo ? "流れて"
    futures += echo ? "くるよ?"

    for (future <- futures.toArray) {
      val res = Await.result(future, timeout.duration)
      res match {
        case msg: String => println(msg)
      }
    }

    sys.shutdown()
  }
}

動かしてみると、たしかに遅れて流れてくる。 では、並列に動かすには?

とりあえず、systemを複数作ってみる。ついでなのでHTTPでgoogleのトップページも雑に叩く。

import akka.actor.{Actor,ActorSystem,Props}
import akka.pattern.ask
import akka.pattern.gracefulStop
import akka.util.Timeout
import scala.concurrent.Future
import scala.concurrent.Await
import scala.concurrent.duration._
import scalaj.http._
import java.lang.Object

class DelayEchoActor extends Actor {
  def receive = {
    case msg: String =>
      import dispatch._, Defaults._
      Thread.sleep(1000)
      sender ! msg
  }
}

class HttpGetRequestActor extends Actor {
  def receive = {
    case url: String =>
      val response: HttpResponse[String] = Http(url).asString
      sender ! response
  }
}

object HelloWorld {
  def main(args: Array[String]) = {
    val echo1Sys = ActorSystem("echo1")
    val echo2Sys = ActorSystem("echo2")
    val http1Sys = ActorSystem("http1")
    val http2Sys = ActorSystem("http2")
    val echo1 = echo1Sys.actorOf(Props[DelayEchoActor])
    val echo2 = echo2Sys.actorOf(Props[DelayEchoActor])
    val http1 = http1Sys.actorOf(Props[HttpGetRequestActor])
    val http2 = http2Sys.actorOf(Props[HttpGetRequestActor])

    implicit val timeout = Timeout(10 seconds)

    val futures = scala.collection.mutable.ArrayBuffer.empty[Future[Any]]
    futures += echo1 ? "あれ?"
    futures += echo2 ? "文字列が"
    futures += echo1 ? "遅れて"
    futures += echo2 ? "流れて"
    futures += echo1 ? "くるよ?"
    futures += http1 ? "http://www.google.co.jp/"
    futures += http2 ? "http://www.google.co.jp/"

    for (future <- futures.toArray) {
      val res = Await.result(future, timeout.duration)
      res match {
        case response: HttpResponse[String] => println(response.body)
        case javaObject: Object => println(javaObject.toString())
      }
    }
  }
}

なるほど。並列に動く。 しかし、こんなめんどくさい感じなわけがないし、なんか、resに変なのがくるし、おかしい。(とりあえずjava.lang.Objectで受けてtoStringするという漢らしいことをしている。)

コードを追ってみるとActorSystem -> LocalActorRef -> ActorCell -> Deployerという要素が見えてきたがキリが無いので諦めてドキュメントに目を移す。 ドキュメントを斜め読みする。ふむ。なんかconfigというのがあるらしい。 akka.actor.deploymentnr-of-instancesというやつがいる。これか?

となったところで、電池が切れそう。

結論

ドキュメント読んでから使え。

支援

Vol.3もあるようです:

第3回 Scalaもくもく会@Volare - connpass

気が向いたらその2も書く。