110 votes

Scala acteurs: recevoir vs réagir

Permettez-moi d'abord de dire que j'ai beaucoup de Java de l'expérience, mais ont récemment été intéressé dans les langages fonctionnels. Récemment, j'ai commencé à regarder Scala, ce qui semble être une très belle langue.

Cependant, j'ai lu à propos de Scala framework d'Acteur dans la Programmation Scala, et il y a une chose que je ne comprends pas. Dans le chapitre 30.4 il est dit que l'utilisation d' react au lieu de receive permet de ré-utiliser les threads, ce qui est bon pour la performance, puisque les threads sont chers dans la JVM.

Est-ce à dire que, aussi longtemps que je me souviens de l'appel react au lieu de receive, je peux commencer comme beaucoup d'Acteurs que j'aime? Avant la découverte de la Scala, j'ai été jouer avec Erlang, et l'auteur de la Programmation Erlang vante le frai plus de 200 000 processus sans casser une sueur. Je déteste faire ça avec les threads Java. Ce genre de limites, je suis à la recherche de Scala par rapport à Erlang (et Java)?

Aussi, comment est-ce fil de ré-utiliser le travail en Scala? Supposons, pour simplifier, que je n'ai qu'un seul thread. Tous les acteurs que j'ai commencer à exécuter séquentiellement dans ce fil, ou sera une sorte de basculement de tâches? Par exemple, si je commence à les deux acteurs de ping-pong des messages les uns aux autres, je risque de blocage si ils ont commencé dans le même thread?

Selon la Programmation Scala, écrit acteurs à utiliser react est plus difficile que dans receive. Cela semble plausible, car react n'a pas de retour. Cependant, le livre montre comment vous pouvez mettre un react à l'intérieur d'une boucle à l'aide de Actor.loop. Comme un résultat, vous obtenez

loop {
    react {
        ...
    }
}

ce qui, pour moi, semble assez similaire à

while (true) {
    receive {
        ...
    }
}

qui est utilisé plus tôt dans le livre. Pourtant, le livre dit que "dans la pratique, les programmes auront besoin au moins de quelques receives'". Donc ce qui me manque ici? Que peut - receive faire react ne peut pas, en plus de retour? Et pourquoi dois-je prendre soin?

Enfin, en venant à la base de ce que je ne comprends pas: le livre garde de mentionner qu'à l'aide de react permet de jeter la pile d'appel pour utiliser de nouveau le fil. Comment cela fonctionne? Pourquoi est-il nécessaire de jeter la pile d'appel? Et pourquoi la pile d'appel à être jetés quand une fonction se termine par la levée d'une exception (react), mais pas lorsqu'il se termine par un retour (receive)?

J'ai l'impression que la Programmation Scala a été dissimuler certaines des questions clés ici, ce qui est dommage, parce que sinon c'est vraiment un excellent livre.

78voto

Daniel C. Sobral Points 159554

Tout d'abord, chaque acteur de l'attente sur receive occupe un thread. Si elle ne reçoit jamais de quoi que ce soit, ce thread ne fera jamais rien. Un acteur sur l' react n'occupent pas de thread jusqu'à ce qu'il reçoit quelque chose. Une fois qu'il reçoit quelque chose, un fil est alloué, et il est initialisé.

Maintenant, l'initialisation de la partie est importante. Un thread de réception est prévu de retourner quelque chose, une réaction fil n'est pas. Si la pile précédent de l'état à la fin de la dernière react peut être, et est, en tout jeté. Pas besoin d'enregistrer ou de restaurer l'état de la pile rend le fil plus rapide à démarrer.

Il y a différentes raisons pour lesquelles vous voudrez peut-être un ou de l'autre. Comme vous le savez, d'avoir un trop grand nombre de threads en Java n'est pas une bonne idée. D'autre part, parce que vous devez joindre à un acteur d'un fil avant d' react, il est plus rapide d' receive un message qu' react . Donc, si vous avez les acteurs qui reçoivent beaucoup de messages mais n'ont que très peu avec elle, le délai supplémentaire d' react peuvent faire qu'il est trop lent pour vos besoins.

21voto

oxbow_lakes Points 70013

La réponse est "oui" - si vos acteurs ne sont pas de blocage sur quoi que ce soit dans votre code et que vous utilisez react, puis vous pouvez exécuter votre "concurrent" du programme dans un seul thread (essayez de définir le système de propriété actors.maxPoolSize à trouver).

L'une des raisons les plus évidentes pourquoi il est nécessaire de jeter la pile d'appel est que sinon, le loop méthode de finir dans un StackOverflowError. Comme il est, le cadre plutôt habilement se termine en react en jetant un SuspendActorException, qui est capturé par le code de boucle qui exécute alors l' react via l' andThen méthode.

Jetez un oeil à l' mkBody méthode de Actor , puis l' seq moyen de voir comment la boucle reporte lui-même - terriblement intelligent trucs!

20voto

Ashwin Points 373

Ces déclarations de "jeter la pile" confondre moi aussi depuis un moment et je pense que je l'obtenir maintenant et ce que j'ai compris, maintenant. En cas de "recevoir" il y a un thread dédié bloque sur le message (à l'aide de l'objet.wait() sur un écran), ce qui signifie que la pile de thread est disponible et prêt à continuer à partir du point de "l'attente" sur réception d'un message. Par exemple si vous avez le code suivant

  def a = 10;
  while (! done)  {
     receive {
        case msg =>  println("MESSAGE RECEIVED: " + msg)
     }
     println("after receive and printing a " + a)
  }

le thread d'attente dans la réception d'appel jusqu'à ce que le message est reçu, puis continuer sur et imprimer le "après réception et l'impression d'un 10" message et avec la valeur de "10", qui est dans le cadre de la pile avant le thread bloqué.

En cas de réagir n'est pas thread dédié, l'ensemble du corps de la méthode de réagir méthode est capturée comme une fermeture et est exécuté par certains thread arbitraire sur l'acteur de la réception d'un message. Cela signifie que uniquement les déclarations qui peuvent être saisies comme une fermeture seul sera exécuté, et c'est là que le type de retour de "Rien" en vient à jouer. Considérons le code suivant

  def a = 10;
  while (! done)  {
     react {
        case msg =>  println("MESSAGE RECEIVED: " + msg)
     }
     println("after react and printing a " + a) 
  }

Si réagir a un type de retour void, ça voudrait dire qu'il est légal d'avoir des instructions après la "réagir" appel ( dans l'exemple, l'instruction println qui imprime le message "après réagir et l'impression d'un 10"), mais en réalité, ce ne serait jamais exécutés comme étant seulement le corps de la "réagir" la méthode est capturé et séquencé pour l'exécution ultérieure (sur l'arrivée d'un message). Étant donné que le contrat de réagir a le type de retour de "Rien" il ne peut y avoir déclarations à la suite de réagir, et là il n'y a aucune raison de maintenir la pile. Dans l'exemple ci-dessus, la variable "a" n'aurait pas à être maintenu tant que les instructions après la réagir les appels ne sont pas exécutées. Notez que toutes les variables nécessaires par l'organisme de réagir est déjà être capturé comme une fermeture, de sorte qu'il peut exécuter l'amende juste.

La java framework d'acteur Kilim en fait de la maintenance de la pile par la sauvegarde de la pile qui se déroula sur les réagissent reçois un message.

8voto

Hexren Points 81

Juste de le pour avoir ici :

Programmation sans Inversion de contrôle basé sur des événements

Ces documents sont liées à la scala api pour acteur et constituent le cadre théorique de la mise en œuvre de l’acteur. Cela comprend pourquoi réagir ne reviendront jamais.

0voto

user3407472 Points 1

Je n'ai pas fait d'importants travaux avec scala /akka, cependant je comprends qu'il y est une différence très significative dans la façon dont les acteurs sont prévues. Akka est juste une puce de pool de threads qui est de tranches de temps d'exécution des acteurs... Chaque tranche de temps aura un message d'exécution à l'achèvement par un acteur à la différence en Erlang, qui pourrait être par l'instruction?!

Cela m'amène à penser que de réagir est mieux comme ça laisse le thread en cours afin de tenir compte des autres acteurs pour la planification de où la que de recevoir "pourrait" faire participer le thread en cours pour poursuivre l'exécution d'autres messages pour le même acteur.

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