学习Akka项目断断续续弄了好久,今天刚好把SBT装好,顺便也将之前遗留的Akka Demo的问题解决掉了,跟大家分享一下~
1.准备工作
(1)安装Akka,到Akka官网下载一个安装包就可以了,地址: http://akka.io/downloads/?_ga=1.235296577.1332829892.1429753844
(2)安装STB,地址:http://www.scala-sbt.org/download.html
需要注意的两点:
a. 在需要创建工程的目录下,如E:\SBT,编写文件sbt.bat,内容如下:
set SCRIPT_DIR=%~dp0
java %SBT_OPTS% -Xms512M -Xmx512M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M -jar "%SCRIPT_DIR%sbt-launch.jar" %*
b. 安装完后,可以在sbt的bin目录下找到sbt-launch.jar,与sbt.bat放在同一目录下
c.点击sbt.bat,就可以运行sbt了,这个过程中需要很长时间下载一些依赖包,比较麻烦。下载完后进入cmd下,执行sbt命令查看安装是否成功。
(3) 下载scala,地址:http://www.scala-lang.org/download/
注意,用Scala开发Akka项目时,两者的版本号要对应起来,否则很容易报错。笔者用的scala版本是2.11.5,Akka版本是2.3.11
2. 创建Akka工程
准备工作做好了之后,就可以创建Akka工程了。将两个例子,一个是计算圆周率的Pi(参考http://www.gtan.com/akka_doc/intro/getting-started-first-scala.html),另一个是
Akka Remote(参考http://alvinalexander.com/scala/simple-akka-actors-remote-example )
2.1 运用Akka实现Pi的近似计算
(1)在目录E:\SBT下创建工程目录 ,如PiProject ,然后按照下面的示意图创建目录和文件
HelloRemote/ |-- build.sbt |-- src |-- main │ +-- scala │ +-- Pi.scala其中,Pi.scala的内容如下:
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
import akka.actor._
import akka.routing.RoundRobinRouter
//import akka.util.Duration
//import akka.util.duration._
import scala.concurrent.duration._
object Pi {
def main(args:Array[String]){
calculate(4, 10000, 10000)
}
// 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
}
}
说明:Akka2.0官方中文版(http://www.gtan.com/akka_doc/intro/getting-started-first-scala.html)中计算Pi的例子缺少了 main()函数,以及依赖包duration与此示例也有所不同。
(2)运行
在cmd下进入工程目录 E:\SBT\PiProject,执行 sbt run 命令,就可以得到计算结果:
2.2 运用STB构建Akka Remote项目
第一个示例Pi是本地实现Akka的过程,此处给出实现远程Akka Remote的例子,参考http://alvinalexander.com/scala/simple-akka-actors-remote-example
(1) Remote工程,创建工程目录 E:\SBT\HelloRemote,然后按照如下示意图创建目录和文件
HelloRemote/ |-- build.sbt |-- src |-- main │ |-- java │ |-- resources │ │ +-- application.conf │ +-- scala │ +-- remote │ +-- HelloRemote.scala +-- test |-- java |-- resources +-- scala
其中,build.sbt 内容如下:
name := "HelloRemote" version := "1.0" scalaVersion := "2.11.5" resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/" libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor" % "2.3.11", "com.typesafe.akka" %% "akka-remote" % "2.3.11" )
其中,配置文件application.conf 内容如下,此例Akka的版本号为2.3, Akka2.1的版本略有不同:
# akka 2.3 akka { loglevel = "INFO" actor { provider = "akka.remote.RemoteActorRefProvider" } remote { enabled-transports = ["akka.remote.netty.tcp"] netty.tcp { hostname = "127.0.0.1" port = 5150 } log-sent-messages = on log-received-messages = on } }
HelloRemote.scala内容如下:
package remote import akka.actor._ object HelloRemote extends App { val system = ActorSystem("HelloRemoteSystem") val remoteActor = system.actorOf(Props[RemoteActor], name = "RemoteActor") remoteActor ! "The RemoteActor is alive" } class RemoteActor extends Actor { def receive = { case msg: String => println(s"RemoteActor received message '$msg'") sender ! "Hello from the RemoteActor" } }
(2) Local工程,Local工程的内容和过程与Remote大部分都很相似
首先创建目录,E:\SBT\HelloLocal,然后创建其他内容:
HelloLocal/ |-- build.sbt |-- src |-- main │ |-- java │ |-- resources │ │ +-- application.conf │ +-- scala │ +-- local │ +-- Local.scala +-- test |-- java |-- resources +-- scala
其中build.sbt内容与Remote一样,application.config
# akka 2.3 akka { loglevel = "INFO" actor { provider = "akka.remote.RemoteActorRefProvider" } remote { enabled-transports = ["akka.remote.netty.tcp"] netty.tcp { hostname = "127.0.0.1" port = 0 } log-sent-messages = on log-received-messages = on } }
HelloLocal.scala内容如下:
package local import akka.actor._ object Local extends App { implicit val system = ActorSystem("LocalSystem") val localActor = system.actorOf(Props[LocalActor], name = "LocalActor") // the local actor localActor ! "START" // start the action } class LocalActor extends Actor { // create the remote actor (Akka 2.3 syntax) val remote = context.actorFor("akka.tcp://HelloRemoteSystem@127.0.0.1:5150/user/RemoteActor") var counter = 0 def receive = { case "START" => remote ! "Hello from the LocalActor" case msg: String => println(s"LocalActor received message: '$msg'") if (counter < 5) { sender ! "Hello back to you" counter += 1 } } }
(3)运行
先运行Remote,cd 进入HelloRemote目录,键入sbt run命令,开启remote actor system
然后在一个新的cmd窗口进入 HellLocal目录,键入sbt run命令,开启local actor system
运行结果如下:
remote:
local:
大工告成!