2010-07-28 23 views
5

Avvio di due attori remoti su un host che riproduce solo ciò che viene loro inviato. Creo quindi un altro attore che manda un certo numero di messaggi (usando !!) a entrambi gli attori e tiene un elenco di oggetti Future che contengono le risposte di questi attori. Quindi eseguo il ciclo su questa lista recuperando il risultato di ogni futuro. Il problema è che il più delle volte alcuni futuri non tornano mai, anche se l'attore sostiene di aver inviato la risposta. Il problema si verifica in modo casuale, a volte può passare attraverso l'intera lista, ma il più delle volte si blocca a un certo punto e si blocca indefinitamente.si blocca quando si utilizzano più future con più attori remoti

Ecco il codice che produce il problema sulla mia macchina:

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() 
    } 
} 

Che cosa sto facendo di sbagliato?

+0

Ho anche provato a utilizzare una porta diversa per ciascun attore, ma ottenere lo stesso risultato. – Kevin

risposta

2

sto cercando di indovinare il problema è dovuto a questa linea:

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

in cui si ciclo tra tutti il ​​vostro futuro e il blocco su uno alla volta, in attesa che il suo risultato. Il blocco dei futures è generalmente una cattiva idea e dovrebbe essere evitato. Quello che vuoi invece è specificare un'azione da eseguire quando il risultato del futuro è disponibile. Prova questo:

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

Ecco un modo alternativo per dire che con una di comprensione:

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

This blog entry è un ottimo fondo sul problema di bloccare sui future e come monade futuri superarla.

+0

Grazie per la tua risposta, penso di aver capito meglio il problema ora. Tuttavia, questo bit di codice che hai fornito agisce anche in modo strano. Elabora il primo futuro e quindi termina il programma senza generare un'eccezione. Ho anche provato a utilizzare Futures.awaitAll (10000, futuri), ma anche dopo 10 secondi mancano ancora i risultati. – Kevin

+0

Termina perché si chiama exit() dopo il ciclo. Il ciclo tornerà immediatamente con il mio codice perché non blocca più, quindi non vuoi semplicemente uscire più lì. –

+0

no, termina prima, ho aggiunto istruzioni di stampa e loop e molte altre cose di debug. Capisco che questo ciclo non bloccherà, ma nulla dopo quella riga viene elaborato. Qualche idea sul perché Futures.awaitAll non funzioni? Sembra che sia stato scritto appositamente per questo tipo di compito. – Kevin

0

Ho visto anche un caso simile. Quando il codice all'interno del thread genera determinati tipi di eccezioni ed uscite, il corrispondente future.get non restituisce mai. Si può provare a sollevare un'eccezione di java.lang.Error contro java.lang.NoSuchMethodError. Il futuro corrispondente di quest'ultimo non tornerà mai più.

Problemi correlati