views:

96

answers:

1

I start two remote actors on one host which just echo whatever is sent to them. I then create another actor which sends some number of messages (using !! ) to both actors and keep a List of Future objects holding the replies from these actors. Then I loop over this List fetching the result of each Future. The problem is that most of the time some futures never return, even thought the actor claims it has sent the reply. The problem happens randomly, sometimes it will get through the whole list, but most of the time it gets stuck at some point and hangs indefinitely.

Here is some code which produces the problem on my machine:

Sink.scala:

import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.Exit
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._

object Sink {
  def main(args: Array[String]): Unit = {
     new RemoteSink("node03-0",43001).start()
     new RemoteSink("node03-1",43001).start()
   }
}
class RemoteSink(name: String, port: Int) extends Actor
{
 def act() {
    println(name+" starts")
    trapExit=true
    alive(port)
    register(Symbol(name),self)

    loop {
        react {
            case Exit(from,reason) =>{
                    exit()
            }
            case msg => reply{
                    println(name+" sending reply to: "+msg)
                    msg+" back at you from "+name
                }
        }
    }
 }
}

Source.scala:

import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.remote.Node;
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._

object Source {
    def main(args: Array[String]):Unit = {
        val peer = Node("127.0.0.1", 43001)
        val source = new RemoteSource(peer)
        source.start()
    }
}
class RemoteSource(peer: Node) extends Actor
{
    def act() {
        trapExit=true
        alive(43001)
        register(Symbol("source"),self)

        val sinks = List(select(peer,Symbol("node03-0"))
                                   ,select(peer,Symbol("node03-1"))
                                )
        sinks.foreach(link)

        val futures = for(sink <- sinks; i <- 0 to 20) yield    sink !! "hello "+i
        futures.foreach( f => println(f()))

        exit()
    }
}

What am I doing wrong?

+1  A: 

I'm guessing your problem is due to this line:

futures.foreach( f => println(f()))

in which you loop through all your futures and block on each in turn, waiting for its result. Blocking on futures is generally a bad idea and should be avoided. What you want to do instead is specify an action to carry out when the future's result is available. Try this:

futures.foreach(f => f.foreach(r => println(r)))

Here's an alternate way to say that with a for comprehension:

for (future <- futures; result <- future) { println(result) }

This blog entry is an excellent primer on the problem of blocking on futures and how monadic futures overcome it.

pelotom
Thanks for your reply, I think I understand the problem better now. However, this bit of code you provided also acts strangely. It processes the first future and then terminates the program without throwing an exception. I also tried using Futures.awaitAll(10000,futures), but even after 10 seconds there are still missing results.
Kevin
It terminates because you call exit() after the loop. The loop will return immediately with my code because it's no longer blocking, so you don't want to simply exit there any more.
pelotom
no, it terminates before that, I have added print statements and loops and lots of other debugging stuff. I understand that this loop will not block, but nothing after that line gets processed.Any idea why Futures.awaitAll doesn't work? It seems like it was written specifically for this kind of task.
Kevin