Reputation: 165
Can any of you please help me in understanding the basic message passing in scala using Actor Model?
I'm trying to write a simple program with 3 actors.
Actor "BossActor" creates 2 actors "Actor1" and "Actor2"
"Actor1" takes 2 integer arguments -> finds their sum -> passes the sum to Actor2
"Actor2" prints the sum
package actorsSum
import scala.actors.Actor
import scala.actors.Actor._
case object BossActor
case object Actor1
case object Actor2
object SumOf2Numbers extends App
{
print ("Enter Num1 : ")
val Num1 = readInt()
print ("Enter Num2 : ")
val Num2 = readInt()
var Sum = 0
val bossActor = new BossActor(Num1,Num2,Sum)
bossActor.start
}
/** Boss Actor which creates and controls all subsequent actors */
class BossActor(Num1: Int, Num2: Int, Sum: Int) extends Actor {
def act() {
val act1 = new Actor1(Num1,Num2)
val act2 = new Actor2(Sum)
act1.start
act2.start
}
}
/** Actor to find sum of the numbers */
class Actor1 (Num1: Int, Num2: Int) extends Actor {
def act() {
val Grandtotal = Num1 + Num2
/** send "Grandtotal" to Actor2 */
// act2 ! Grandtotal
}
}
/** Actor to print the sum */
class Actor2(Sum: Int) extends Actor {
def act() {
react{
/** print the sum */
case Actor1 => println ("Sum: " + Sum)
case Sum => println ("Sum: " + Sum)
}
}
}
Upvotes: 2
Views: 2087
Reputation: 24413
I would take a different approach. Actors receive messages and react to them. So what you should do is build an actor that receives requests to sum 2 numbers and send them to a receiver that is also specified in the message. That could look like this:
import scala.actors.Actor
case class Sum(x: Int, y: Int)
class SumActor extends Actor {
def act = {
loop {
receive {
case (Sum(x,y), receiver: Actor) => receiver ! x+y
}
}
}
}
class Receiver extends Actor {
def act = {
loop {
receive {
case x: Int => println("Received: " + x)
}
}
}
}
val sumActor = new SumActor
val receiver = new Receiver
sumActor.start
receiver.start
sumActor ! Sum(3,4) -> receiver
You should also take a look at Akka, as it will replace the scala actors in future releases of scala and is way more powerful. But to understand the basics of actors it is sufficient to start with scala actors.
Upvotes: 3
Reputation: 3608
Firstly here is the running code:
import scala.actors.Actor
import scala.actors.Actor._
object Main extends App {
print("Enter first number: ")
private[this] val num1 = readInt()
println(num1)
print("Enter second number: ")
private[this] val num2 = readInt()
println(num2)
private[this] val boss = new BossActor(num1, num2)
boss.start()
}
case object Stop
class BossActor(num1: Int, num2: Int) extends Actor {
def act {
val sumer = new SumActor()
val printer = new PrintingActor()
sumer.start()
printer.start()
sumer ! num1
sumer ! num2
receive {
case i: Int => printer ! i
}
sumer ! Stop
printer ! Stop
exit()
}
}
class SumActor extends Actor {
private[this] var firstOption: Option[Int] = None
def act() {
loop {
react {
case i: Int => if (firstOption.isDefined) {
sender ! i + firstOption.get
firstOption = None
} else {
firstOption = Some(i)
}
case Stop => exit()
}
}
}
}
class PrintingActor extends Actor {
def act() {
loop {
react {
case Stop => exit()
case e => println(e)
}
}
}
}
I read the numbers like you do. Than I create a new BossActor
. Next the boss sends the received Int
to the SumActor
. The sumer adds the two values and returns them to the boss. The boss sends the sum to the PrintingActor
. The printer prints the numbers. Afterwards the boss sends atermination message to his actors and terminates himself. This might be improved by sending the boss the two Int
, but in this simple example it might show how to create an Actor
wtih parameter.
Upvotes: 1
Reputation: 38045
First of all: sender(Actor1) should know about receiver(Actor2), so you should create and start receiver before sender, and pass receiver as constructor argument to sender.
Don't use var
to share actor's state.
Using case objects as messages is a good idea, but you should use case class to send some value.
import scala.actors.Actor
import scala.actors.Actor._
case class Sum(i: Int)
class Sender(a1: Int, a2: Int, receiver: Actor) extends Actor {
def act() {
receiver ! Sum(a1 + a2)
}
}
class Receiver extends Actor {
def act() {
react {
case Sum(i) => println("Sum: " + i)
}
}
}
val receiver = new Receiver().start()
val sender = new Sender(1, 2, receiver).start()
You can use some helper methods from object Actor:
import scala.actors.Actor._
val receiver = actor { react { case i: Int => println("Sum: " + i) } }
val sender = actor { receiver ! 1 + 2 }
Upvotes: 1