Pergunta

O resposta a uma pergunta recente da mina indicaram que um ator processados ??suas mensagens um de cada vez . Isso é verdade? Não vejo nada que diz explicitamente que (em Programação em Scala ), que contém o seguinte trecho (pp. 593)

Se [o método react] encontra uma mensagem que pode ser manuseado, [ele] irá agendar a manipulação dessa mensagem para execução posterior e lançar uma exceção

(ênfase minha). Duas perguntas (e mutuamente exclusivos) relacionados:

  1. Assumindo que um ator poderia processar várias mensagens simulatenously, como posso forçar um ator para processar mensagens 1 de cada vez (se é isso que eu gostaria de fazer)? (Usando receive?)
  2. Assumindo uma processos ator mensagens um de cada vez, como eu melhor implementar um ator que na verdade poderia processar mensagens simultaneamente

edit: fazer um pouco de testes parece confirmar que estou errado e que os atores são realmente seqüencial. Por isso é a pergunta # 2, que eu preciso responder

Foi útil?

Solução

Atores processar uma mensagem de cada vez. O padrão clássico para processar várias mensagens é ter um coordenador frente ator por um grupo de atores de consumo. Se você usar reagir em seguida, a piscina do consumidor pode ser grande, mas ainda só usar um pequeno número de threads JVM. Aqui está um exemplo onde eu criar um pool de 10 consumidores e um coordenador para a frente para eles.

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)

testa Este código para ver qual consumidor está disponível e envia uma solicitação para que o consumidor. Alternativas são para atribuir apenas aleatoriamente para os consumidores ou para usar um programador de round robin.

Dependendo do que você está fazendo, você pode ser melhor servido com Futuros de Scala. Por exemplo, se você realmente não precisa de atores, em seguida, todo o maquinário acima poderia ser escrito como

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

Outras dicas

Eu acho que a resposta é que um Actor não pode lidar com mensagens aynchronously. Se você tem um Actor que deve estar a ouvir mensagens onde estas mensagens podem ser tratadas de forma assíncrona , então ele poderia ser escrito assim:

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 você quiser fazer várias coisas, então você deve estar usando múltiplos atores. Toda a razão para usar atores é dividir o trabalho entre vários processos independentes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top