0

I have to write a code such that Actor A produces an infinite stream of numbers which Actor B consumes. Actor A outputs the sequence: x , f(x), g(f(x)) etc where f(x) = 10 if x is 0 and 3x otherwise, and where g(x) is x/2. i.e:

Output: x =0, f(x)=10, g(f(x)=5 (3 messages) then next 3 messages should be f(g(f(x)) , g(f(g(f(x))) , f(g(f(g(f(x)))) and their value...where the inner function becomes x each time to compute the result for the adjacent result

Actor B deals with numbers 3 at a time and it should print each triple tabulated on the same line with the average of the 3 numbers.

The value (0) is passed to ActorA from the main method.

My attempt:

import akka.actor._

class ActorA(processB:ActorRef) extends Actor with ActorLogging{

  def f(x : Int) = if(x == 0) 10 else 3 * x
  def g(x : Int) = x / 2

  def receive = {
   case 0 =>
      val x = 0
      //processB !  (x)
     // processB ! (f(x))
    // processB ! (g(f(x)))
      println( (f(x)))
      println((g(f(x))))
    /*case Stop =>
        Console.println("Stop")
       processB ! Stop
       context stop self    */
   }
}

class ActorB extends Actor with ActorLogging{

 def receive = {
        case ActorA =>


        case Stop =>
          Console.println("Stop")
          exit()    
 }
}

case object ActorA
case object ActorB
case object Stop

object messages {
  def main(args: Array[String]) :Unit = {
    val system = ActorSystem("actors")
    val processB = system.actorOf(Props[ActorB])  
    val actorA = system.actorOf(Props(new ActorA(processB)))   
    actorA ! 0
  }
}

How to produce an INFINITE number of messages and can I deal with them 3 at a time? Thanks

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
user2947615
  • 491
  • 3
  • 5
  • 14

2 Answers2

2

To get an infinite sequence you can use a Stream.

Derek Wyatt has a good blog article on them and how generating Fibonacci numbers works:

http://www.derekwyatt.org/2011/07/29/understanding-scala-streams-through-fibonacci/

You can use the same basic principle for your sequence which, if I understand correctly, is alternately applying the f and g function on the previous value in the stream.

You can write that as follows:

lazy val stream: Stream[Int] = x #:: stream.zipWithIndex.map { 
   case (p,i) => if (i%2 == 0) f(p) else g(p) 
}

You can then split the stream into chunks of 3 using grouped, Here I've done that and then converted the resulting Stream[Int], each of size 3, into a tuple for convenience:

val chunks: Iterator[(Int,Int,Int)] = stream.grouped(3).map { s => 
   (s.head, s.tail.head, s.tail.tail.head) 
}

You can then make use of that however you want, sending the tuple to the other actor if you so wish.

At the other side you can match that tuple as follows:

case (a:Int, b:Int, c:Int) => ...
Steve Sowerby
  • 1,136
  • 1
  • 7
  • 7
1

Actors have inboxes that will fill up, and there's no inherent backpressure to tell the producer to wait. See: How to use Akka BoundedMailBox to throttle a producer

In general, you'll probably want B to explicitly send messages to A asking for data.

Community
  • 1
  • 1
Rob Starling
  • 3,868
  • 3
  • 23
  • 40