28 votes

Les acteurs de Scala peuvent-ils traiter plusieurs messages simultanément?

La réponse à une récente question de la mienne a indiqué qu'un acteur transformés ses messages un à un. Est-ce vrai? Je ne vois rien qui dit explicitement que (dans la Programmation Scala), qui contient de l'extrait de code suivant (pp. 593)

Si [l' react méthode] trouve un message qui peut être traitée, [il] s'calendrier de la manipulation de ce message pour plus tard, d'exécution et de lever une exception

(L'emphase est de mon propre). Les deux (et mutuellement exclusives) questions:

  1. Dans l'hypothèse d'un acteur peut traiter plusieurs messages simulatenously, comment puis-je la force d'un acteur pour traiter les messages 1 à un moment (si c'est ce que je souhaite faire)? (à l'aide d' receive?)
  2. Dans l'hypothèse d'un acteur traite les messages un à un, comment pourrais-je mieux de mettre en œuvre un acteur qui, en fait, pourrait traiter les messages simultanément

edit: en faisant un peu de tests semble confirmer que je me trompe et que les acteurs sont en effet séquentiel. Il est donc question #2 j'ai besoin de réponse

26voto

James Iry Points 14192

Les acteurs du processus, un message à la fois. Le schéma classique pour traiter plusieurs messages est d'avoir un coordonnateur de l'acteur avant pour un bassin de consommation des acteurs. Si vous utilisez réagir alors le consommateur de la piscine peut être grande, mais seulement utiliser un petit nombre de JVM threads. Voici un exemple où j'ai créer un pool de 10 consommateurs et un coordinateur de l'avant pour eux.

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)

Ce code tests pour voir qui à la consommation est disponible et envoie une demande pour le consommateur. Les Alternatives sont juste d'attribuer au hasard, à la consommation ou à l'utilisation d'un tournoi à la ronde du planificateur.

En fonction de ce que vous faites, vous pourriez être mieux servis avec de la Scala à Terme. Par exemple, si vous n'avez pas vraiment besoin des acteurs de toutes les machines ci-dessus peut être écrite comme

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

6voto

oxbow_lakes Points 70013

Je pense que la réponse est qu'un Actor ne peut pas gérer les messages de manière aynchrone. Si vous avez un Actor qui devrait écouter les messages où ces messages peuvent être traités de manière asynchrone , alors il pourrait être écrit comme ceci:

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

0voto

mamboking Points 2463

Si vous voulez faire plusieurs choses, vous devez utiliser plusieurs acteurs. La seule raison d'utiliser des acteurs est de diviser le travail entre plusieurs processus indépendants.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X