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"
View Code

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

  }
}
View Code

 注:文献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

posted on 2014-04-08 16:53  hequn8128  阅读(847)  评论(0编辑  收藏  举报

导航