akka入门
Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。
akka官网,见参考文献1.
akka官方documents中文版,见参考文献2.
编写一个初级sbt akka程序,计算Pi,详细可参考文献2。
1.创建工程的文件夹,myproject。文件夹下创建build.sbt,如下。sbt的安装和使用见参考文献3.
name := "My Project" version := "1.0" scalaVersion := "2.10.3" resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/" libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.3.1"
2.myproject下创建src/main/scala目录来存放源码,Pi.scala。
package com.hequn.akka import akka.actor._ import akka.routing.RoundRobinRouter import scala.concurrent.duration._ object Pi extends App { calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000) sealed trait PiMessage case object Calculate extends PiMessage case class Work(start: Int, nrOfElements: Int) extends PiMessage case class Result(value: Double) extends PiMessage case class PiApproximation(pi: Double, duration: Duration) class Worker extends Actor { def calculatePiFor(start: Int, nrOfElements: Int): Double = { var acc = 0.0 for (i ← start until (start + nrOfElements)) acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1) acc } def receive = { case Work(start, nrOfElements) ⇒ sender ! Result(calculatePiFor(start, nrOfElements)) // perform the work } } class Master(nrOfWorkers: Int, nrOfMessages: Int, nrOfElements: Int, listener: ActorRef) extends Actor { var pi: Double = _ var nrOfResults: Int = _ val start: Long = System.currentTimeMillis val workerRouter = context.actorOf( Props[Worker].withRouter(RoundRobinRouter(nrOfWorkers)), name = "workerRouter") def receive = { case Calculate ⇒ for (i ← 0 until nrOfMessages) workerRouter ! Work(i * nrOfElements, nrOfElements) case Result(value) ⇒ pi += value nrOfResults += 1 if (nrOfResults == nrOfMessages) { // Send the result to the listener listener ! PiApproximation(pi, duration = (System.currentTimeMillis - start).millis) // Stops this actor and all its supervised children context.stop(self) } } } class Listener extends Actor { def receive = { case PiApproximation(pi, duration) ⇒ println("\n\tPi approximation: \t\t%s\n\tCalculation time: \t%s" .format(pi, duration)) context.system.shutdown() } } def calculate(nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) { // Create an Akka system val system = ActorSystem("PiSystem") // create the result listener, which will print the result and shutdown the system val listener = system.actorOf(Props[Listener], name = "listener") // create the master val master = system.actorOf(Props(new Master( nrOfWorkers, nrOfMessages, nrOfElements, listener)), name = "master") // start the calculation master ! Calculate } }
注:文献2中计算Pi的例子,duration已经不在akka.util里,编译会不通过,需改成import scala.concurrent.duration._
程序中trait是特质,类似于java中的接口。详见参考文献4。sealed是密封类别,详见参考文献5.
3.程序框架图如下。
首先给Master发送计算的指令,Master然后向workerRouter发送work消息,Worker计算完后将结果返回给Master,Master统计结构并返回给Listener。
4.actor的结构。
每个actor都是一个潜在的监管者:如果它创建了子actor来委托处理子任务,它会自动地监管它们。所以,actor自然会形成树形结构。子actor列表维护在actor的上下文中,actor可以访问它。对列表的更改是通过创建(tt class="docutils literal">context.actorOf(...))或者停止(context.stop(child))子actor来实现,并且这些更改会立刻生效。实际的创建和停止操作在幕后以异步的方式完成,这样它们就不会“阻塞”其监管者。子actor列表维护在actor的上下文中,actor可以访问它。
Pi.scala程序中,actor树的结构有两层,父actor是Master,子actor是Worker和Listener。
参考文献:
[1]akka官网:http://akka.io/
[2]akka中文版documents:http://www.gtan.com/akka_doc/index.html
[3]sbt安装和使用:http://www.scala-sbt.org/release/docs/Getting-Started/Setup.html
[4]scala trait:http://developer.51cto.com/art/200909/150722.htm
[5]scala sealed:http://openhome.cc/Gossip/Scala/SealedClass.html