Domanda

La risposta a una mia recente domanda ha indicato che un attore ha elaborato i suoi messaggi uno alla volta . È vero? Non vedo nulla che lo dica esplicitamente (in Programmazione in Scala ), che contiene il seguente frammento (pagg. 593)

  

Se [il metodo reagire ] trova un messaggio che può essere gestito, [esso] pianificherà la gestione di quel messaggio per successive esecuzioni e genererà un'eccezione

(Enfasi mia). Due domande correlate (e reciprocamente esclusive):

  1. Supponendo che un attore possa elaborare più messaggi contemporaneamente, come posso forzare un attore a elaborare i messaggi 1 alla volta (se questo è ciò che desidero fare)? (utilizzando ricevi ?)
  2. Supponendo che un attore elabori i messaggi uno alla volta, come implementare al meglio un attore che in effetti potrebbe elaborare i messaggi contemporaneamente

modifica: fare un po 'di prove sembra confermare che mi sbaglio e che gli attori sono davvero sequenziali. Quindi è la domanda n. 2 alla quale devo rispondere

È stato utile?

Soluzione

Gli attori elaborano un messaggio alla volta. Il modello classico per elaborare più messaggi è quello di avere un attore coordinatore davanti a un pool di attori consumatori. Se si utilizza la reazione, il pool di consumatori può essere grande, ma utilizzerà comunque solo un numero limitato di thread JVM. Ecco un esempio in cui creo un pool di 10 consumatori e un coordinatore 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 verifica se il consumatore è disponibile e invia una richiesta a quel consumatore. Le alternative sono semplicemente assegnare casualmente ai consumatori o utilizzare un pianificatore round robin.

A seconda di ciò che stai facendo, potresti essere meglio servito con i Futures di Scala. Ad esempio, se non hai davvero bisogno di attori, tutte le macchine sopra potrebbero essere scritte 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))

Altri suggerimenti

Penso che la risposta sia che un attore non possa gestire i messaggi in modo asincrono. Se hai un attore che dovrebbe ascoltare i messaggi in cui questi messaggi possono essere gestiti in modo asincrono , potrebbe essere scritto in questo modo:

val actor_ = actor {

  loop {
    react {
      case msg =>
        //create a new actor to execute the work. The framework can then 
        //manage the resources effectively
        actor {
          //do work here
        }
      }
    }
  }

Se vuoi fare più cose, allora dovresti usare più attori. L'intero motivo per utilizzare gli attori è di suddividere il lavoro tra più processi indipendenti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top