Akka(2)Start with first Project - First Part

Akka(2)Start with first Project - First Part
Use actor to calculate the value of Pi.

Create the project
Install the Typesafe akka-scala-sbt project template first.

Try to get the scala akka project template:
>g8 typesafehub/akka-scala-sbt
Akka 2.0 Project Using Scala and sbt
organization [org.example]: com.sillycat.easyakka
name [Akka Project In Scala]: easyakka
akka_version [2.0.1]:
version [0.1-SNAPSHOT]:
Applied typesafehub/akka-scala-sbt.g8 in easyakka

Try to get the scala akka demo source code:
>g8 typesafehub/akka-first-tutorial-scala
Akka 2.0 project using Scala and sbt
organization [org.example]: com.sillycat.easyakka
package [org.example]: com.sillycat.easyakka
name [Akka Pi Calculation Tutorial In Scala]: easyakka
akka_version [2.0.3]:
version [0.1-SNAPSHOT]:
artifact_id [akka-pi-scala]: easyakka
Skipping existing file: easyakka/README
Applied typesafehub/akka-first-tutorial-scala.g8 in easyakka

>cd easyakka
>sbt update
>sbt eclipse

Import the project to my eclipse.

Run the project with simple build tool
>sbt compile
>sbt run

Everything works fine here.

Run it from eclipse:
I just open the file Pi.scala and right click on that and run scala application.

Error Message:
Exception in thread "main" java.lang.NoSuchMethodError: scala.Predef$.augmentString(Ljava/lang/String;)Lscala/collection/immutable/StringOps;

Solution:
That is mostly related to using different versions of Scala.
I change my low version of eclipse and scala to 2.9.2. That works fine. I do not want to speed time to solve the version problem.
I just want to understand how the actor works in akka. So let's move on.

Try to understand the Design and Implementation
Import the package:
import akka.actor._
import akka.routing.RoundRobinRouter
import akka.util.Duration
import akka.util.duration._

Design
Master ----> Worker(N)
<----
Master ----> Listener

Messages:
Calculate - sent to the Master actor to start the calculation
Work - send from the Master actor to the Worker actors
Result - send from the Worker actors to the Master actor
PiApproximation - send from the Master actor to the Listener actor

Messages sent to actors should always be immutable to avoid sharing mutable state. 'case class' make excellent messages.

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)

A sealed trait can be extended only in the same file than its declaration.

Creating the worker
class Worker extends Actor {
//get the start and number
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 //return the latest line
}

//receive the task data from message, sender back once we are done
def receive = {
case Work(start, nrOfElements) =>
sender ! Result(calculatePiFor(start, nrOfElements)) // perform the work
}
}

We send the message back to the sender using the sender reference.

In Akka the sender reference is implicitly passed along with the message so that the receiver can always reply or store away the sender reference for future use.

Creating the master
The master actor is a little bit more involved.

class Master(nrOfWorkers: Int,
nrOfMessages: Int,
nrOfElements: Int,
listener: ActorRef) extends Actor { // listener is a ActorRef we can send message

var pi: Double = _
var nrOfResults: Int = _
val start: Long = System.currentTimeMillis //get the start time

//define the number of workers and using round-robin router
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) // divide the tasks, send all tasks to workerRouter
case Result(value) => // case it is the sender message about result from the worker
pi += value
nrOfResults += 1
if (nrOfResults == nrOfMessages) { //get all the messages back
listener ! PiApproximation(pi, duration = (System.currentTimeMillis - start).millis)
context.stop(self) // stop the master actor
}
}
}

Our master have 3 parameters.
nrOfWorkers how many workers we should start up
nrOfMessages how many chunks to send out to the workers
nrOfElements how big the number chunks send to each worker

The ActorRef is used to report the final result to the outside world.


References:
http://doc.akka.io/docs/akka/2.1.0/
http://doc.akka.io/docs/akka/2.1.0/general/index.html

https://github.com/typesafehub
http://typesafe.com/resources/tutorials/getting-started-with-akka-scala.html#getting-started-with-akka-scala

http://alvinalexander.com/scala/java.lang.nosuchmethoderror-scala.predef.augmentstring-error

http://stackoverflow.com/questions/11203268/what-is-a-sealed-trait
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值