c:\temp>g8 typesafehub/akka-scala-sbt
Akka 2.0 Project Using Scala and sbt
organization [org.example]: akka.tutorial
package [org.example]: akka.tutorial.first.scala
name [Akka Project In Scala]: PI Calculator
akka_version [2.0]:
version [0.1-SNAPSHOT]:
Applied typesafehub/akka-scala-sbt.g8 in pi-calculator
c:\temp>cd pi-calculator
./src/main/scala/akka/tutorial/first/scala/
file in the appropriate folder ( ./src/main/scala/akka/tutorial/first/scala/
) and import the necessary libraries:import akka.actor._
import akka.routing.RoundRobinRouter
import akka.util.Duration
import akka.util.duration._
Master
actor that creates a multitude of Worker
actors and initializes the calculation. To do this, he divides the entire task into small operations and sends these operations for the Worker
to perform to the actors. After performing the operations, the Worker
actors return the results for the aggregation. After the calculation is completed, the Master
actor sends the result Listener
actor, which displays it on the screen.Calculate
- sent to the Master
actor to start the calculationWork
- sent by Master
actor Worker
actors, contains descriptions of the operation to be performedResult
- sent by Worker
actors Master
actorPiApproximation
- sent by Master
Listener
actor to actor, contains the result of the calculation and the time spent on the calculationsealed 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)
Worker
ActorWorker
actor. This is done by mixing the Actor
trait and defining the receive
method. This method is a handler for incoming messages:class Worker extends Actor { // calculatePiFor ... def receive = { case Work (start, nrOfElements) ⇒ sender! Result (calculatePiFor (start, nrOfElements)) // perform the work } }
Work
message handler, which creates a Result
response message after the calculatePiFor
operation and sends it back to the sender. Now let's implement calculatePiFor
: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 }
Master
ActorMaster
actor is a bit more complicated. a cyclic router is created in its constructor to facilitate the distribution of operations between Worker
actors:val workerRouter = context.actorOf ( Props [Worker] .withRouter (RoundRobinRouter (nrOfWorkers)), name = "workerRouter")
Master
Actor. This actor is created with the following parameters:Worker
actorsWorker
actorclass 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 = { // handle messages ... } }
ActorRef
object, which is a reference to the Listener
actor, is passed to the Master
actor. It should be noted that the transfer of messages between actors is always done through such links.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 children context.stop (self) } }
Master
actor stops using the context.stop(self)
command.Listener
ActorPiApproximation
message from the Master
actor, prints the result and stops the actor system: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 () } }
object Pi extends App { calculate (nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000) // actors and messages ... def calculate (nrOfWorkers: Int, nrOfElements: Int, nrOfMessages: Int) { // Create an Akka system val system = ActorSystem ("PiSystem") // create the result listener // 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 } }
sbt
. Then we execute the following sequence of commands:c:\temp\pi-calculator>sbt
[info] Loading project definition from C:\temp\pi-calculator\project
[info] Set current project to PI Calculator (in build file:/C:/temp/pi-calculator/)
> compile
[success] Total time: 0 s, completed 20.03.2012 16:33:03
> run
[info] Running akka.tutorial.first.scala.Pi
Pi approximation: 3.1415926435897883
Calculation time: 423 milliseconds
[success] Total time: 1 s, completed 20.03.2012 16:33:25
> run
[info] Running akka.tutorial.first.scala.Pi
Pi approximation: 3.1415926435897883
Calculation time: 1160 milliseconds
[success] Total time: 2 s, completed 20.03.2012 16:35:16
> run
[info] Running akka.tutorial.first.scala.Pi
Pi approximation: 3.1415926435897905
Calculation time: 388 milliseconds
[success] Total time: 1 s, completed 20.03.2012 16:36:55
> run
[info] Running akka.tutorial.first.scala.Pi
Pi approximation: 3.141592643589789
Calculation time: 372 milliseconds
[success] Total time: 1 s, completed 20.03.2012 16:40:04
Source: https://habr.com/ru/post/140368/
All Articles