attori del processo di un messaggio alla volta. Lo schema classico per elaborare più messaggi è quello di avere un attore coordinatore per un pool di attori consumatori. Se si utilizza reagire, il pool di consumatori può essere grande ma utilizzerà solo un numero limitato di thread JVM. Ecco un esempio in cui creo un pool di 10 consumatori e un coordinatore in primo piano per loro.
import scala.actors.Actor
import scala.actors.Actor._
case class Request(sender : Actor, payload : String)
case class Ready(sender : Actor)
case class Result(result : String)
case object Stop
def consumer(n : Int) = actor {
loop {
react {
case Ready(sender) =>
sender ! Ready(self)
case Request(sender, payload) =>
println("request to consumer " + n + " with " + payload)
// some silly computation so the process takes awhile
val result = ((payload + payload + payload) map {case '0' => 'X'; case '1' => "-"; case c => c}).mkString
sender ! Result(result)
println("consumer " + n + " is done processing " + result)
case Stop => exit
}
}
}
// a pool of 10 consumers
val consumers = for (n <- 0 to 10) yield consumer(n)
val coordinator = actor {
loop {
react {
case msg @ Request(sender, payload) =>
consumers foreach {_ ! Ready(self)}
react {
// send the request to the first available consumer
case Ready(consumer) => consumer ! msg
}
case Stop =>
consumers foreach {_ ! Stop}
exit
}
}
}
// a little test loop - note that it's not doing anything with the results or telling the coordinator to stop
for (i <- 0 to 1000) coordinator ! Request(self, i.toString)
Questo codice consente di verificare quale utente è disponibile e invia una richiesta a tale utente. Le alternative sono assegnate solo in modo casuale ai consumatori o per utilizzare uno scheduler round robin.
A seconda di cosa stai facendo, potresti essere meglio servito con i Futures di Scala. Per esempio, se non hai davvero bisogno di attori, tutti i suddetti macchinari potrebbero essere scritti come
import scala.actors.Futures._
def transform(payload : String) = {
val result = ((payload + payload + payload) map {case '0' => 'X'; case '1' => "-"; case c => c}).mkString
println("transformed " + payload + " to " + result)
result
}
val results = for (i <- 0 to 1000) yield future(transform(i.toString))
fonte
2009-06-17 17:41:26
Davvero non vedo come questa domanda giustifica un downvote. Se riesco a leggere un intero capitolo sugli attori in Programmazione in Scala e non sono sicuro della risposta, è una domanda completamente valida. –
Un singolo attore elabora i messaggi in modo sequenziale perché l'idea è che si possa utilizzare un attore per mediare l'accesso a una risorsa (altrimenti) condivisa e non sarà richiesta alcuna altra sincronizzazione sulla risorsa condivisa.Se i messaggi possono essere elaborati in sequenza, è necessario utilizzare i blocchi all'interno degli attori per garantire che non si verifichino errori di sincronizzazione. –