Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple Scala actor question

Tags:

scala

actor

I'm sure this is a very simple question, but embarrassed to say I can't get my head around it:

I have a list of values in Scala. I would like to use use actors to make some (external) calls with each value, in parallel.

I would like to wait until all values have been processed, and then proceed.

There's no shared values being modified.

Could anyone advise?

Thanks

like image 811
7zark7 Avatar asked Apr 02 '10 03:04

7zark7


2 Answers

There's an actor-using class in Scala that's made precisely for this kind of problem: Futures. This problem would be solved like this:

// This assigns futures that will execute in parallel
// In the example, the computation is performed by the "process" function
val tasks = list map (value => scala.actors.Futures.future { process(value) })

// The result of a future may be extracted with the apply() method, which
// will block if the result is not ready.
// Since we do want to block until all results are ready, we can call apply()
// directly instead of using a method such as Futures.awaitAll()
val results = tasks map (future => future.apply())

There you go. Just that.

like image 151
Daniel C. Sobral Avatar answered Nov 19 '22 04:11

Daniel C. Sobral


Create workers and ask them for futures using !!; then read off the results (which will be calculated and come in in parallel as they're ready; you can then use them). For example:

object Example {
  import scala.actors._
  class Worker extends Actor {
    def act() { Actor.loop { react {
      case s: String => reply(s.length)
      case _ => exit()
    }}}
  }
  def main(args: Array[String]) {
    val arguments = args.toList
    val workers = arguments.map(_ => (new Worker).start)
    val futures = for ((w,a) <- workers zip arguments) yield w !! a
    val results = futures.map(f => f() match {
      case i: Int => i
      case _ => throw new Exception("Whoops--didn't expect to get that!")
    })
    println(results)
    workers.foreach(_ ! None)
  }
}

This does a very inexpensive computation--calculating the length of a string--but you can put something expensive there to make sure it really does happen in parallel (the last thing that case of the act block should be to reply with the answer). Note that we also include a case for the worker to shut itself down, and when we're all done, we tell the workers to shut down. (In this case, any non-string shuts down the worker.)

And we can try this out to make sure it works:

scala> Example.main(Array("This","is","a","test"))
List(4, 2, 1, 4)
like image 23
Rex Kerr Avatar answered Nov 19 '22 04:11

Rex Kerr