2010-07-28 27 views
5

Je démarre deux acteurs distants sur un hôte qui fait écho à tout ce qui leur est envoyé. Je crée ensuite un autre acteur qui envoie un certain nombre de messages (en utilisant !!) aux deux acteurs et garde un objet List of Future contenant les réponses de ces acteurs. Ensuite, je boucle sur cette liste pour aller chercher le résultat de chaque futur. Le problème est que la plupart du temps, certains futurs ne reviennent jamais, même si l'acteur prétend avoir envoyé la réponse. Le problème se produit de manière aléatoire, parfois il traverse toute la liste, mais la plupart du temps, il se bloque à un moment donné et se bloque indéfiniment.programme se bloque lors de l'utilisation de plusieurs futurs avec plusieurs acteurs à distance

Voici un code qui produit le problème sur ma 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() 
    } 
} 

Qu'est-ce que je fais mal?

+0

J'ai également essayé d'utiliser un port différent pour chaque acteur, mais obtenir le même résultat. – Kevin

Répondre

2

Je devine que votre problème est dû à cette ligne:

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

dans lequel vous boucle à travers tous vos contrats à terme et bloc sur chacun à son tour, en attendant le résultat. Bloquer sur les contrats à terme est généralement une mauvaise idée et devrait être évitée. Qu'est-ce que vous voulez faire à la place est de spécifier une action pour effectuer lorsque le résultat du futur est disponible. Essayez ceci:

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

est ici une autre façon de dire que, avec une compréhension pour:

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

This blog entry est une excellente introduction sur le problème de blocage sur l'avenir et comment à terme monadique surmonter.

+0

Merci pour votre réponse, je pense que je comprends mieux le problème maintenant. Cependant, ce morceau de code que vous avez fourni agit étrangement. Il traite le premier futur, puis termine le programme sans lancer d'exception. J'ai également essayé d'utiliser Futures.awaitAll (10000, futures), mais même après 10 secondes, il manque encore des résultats. – Kevin

+0

Il se termine parce que vous appelez exit() après la boucle. La boucle retournera immédiatement avec mon code car elle ne bloque plus, donc vous ne voulez plus simplement quitter. –

+0

non, il se termine avant cela, j'ai ajouté des instructions d'impression et des boucles et beaucoup d'autres choses de débogage. Je comprends que cette boucle ne bloquera pas, mais rien après cette ligne sera traitée. Une idée pourquoi Futures.awaitAll ne fonctionne pas? Il semble qu'il a été écrit spécifiquement pour ce genre de tâche. – Kevin

0

J'ai également vu un boîtier similaire. Lorsque le code à l'intérieur du thread renvoie certains types d'exception et se termine, le fichier future.get correspondant ne retourne jamais. On peut essayer de lever une exception de java.lang.Error vs java.lang.NoSuchMethodError. Le futur correspondant de ce dernier ne reviendrait jamais.