2010-02-22 6 views
11

Je viens de Java, où je soumets Runnable s à un ExecutorService soutenu par un pool de threads. Il est très clair en Java comment définir des limites à la taille du pool de threads.Comment limiter la concurrence lors de l'utilisation d'acteurs dans Scala?

Je suis intéressé par l'utilisation d'acteurs Scala, mais je ne sais pas comment limiter la concurrence. Disons simplement, hypothétiquement, que je crée un service web qui accepte les "jobs". Un travail est soumis avec des demandes POST, et je souhaite que mon service mette en file d'attente le travail, puis renvoie immédiatement 202 Accepted, c'est-à-dire que les travaux sont gérés de manière asynchrone.

Si j'utilise des acteurs pour traiter les tâches dans la file d'attente, comment puis-je limiter le nombre de tâches simultanées traitées?

Je peux penser à quelques façons différentes d'aborder cela; Je me demande s'il existe une meilleure pratique communautaire, ou du moins des approches clairement établies qui sont quelque peu standard dans le monde des Scala.

Une approche à laquelle j'ai pensé est d'avoir un seul acteur coordinateur qui gèrerait la file d'attente et les acteurs du traitement des travaux; Je suppose qu'il pourrait utiliser un champ int simple pour suivre le nombre d'emplois en cours de traitement. Je suis sûr qu'il y aurait quelques gotchyas avec cette approche, cependant, comme s'assurer de suivre quand une erreur se produit afin de décrémenter le nombre. C'est pourquoi je me demande si Scala fournit déjà une approche plus simple ou plus encapsulée à cela.

BTW J'ai essayé de poser cette question a while ago mais je l'ai mal posé.

Merci!

Répondre

5

Vous pouvez remplacer les propriétés système actors.maxPoolSize et actors.corePoolSize qui limitent la taille du pool de threads d'acteur, puis lancent autant de tâches au niveau du pool que vos acteurs peuvent gérer. Pourquoi pensez-vous avoir besoin de throttle vos réactions?

+1

Très utile, merci! Je ne suis pas sûr d'utiliser le terme _throttle_, mais de toute façon, il y a des moments où il faut contraindre le nombre de "processus" simultanés parce que le travail qu'ils font est gourmand en ressources. –

+3

Cette approche pourrait ne pas donner le résultat souhaité. Cela permettra aux tâches d'être mises en file d'attente jusqu'à ce que la mémoire de la machine virtuelle soit épuisée. Limiter le nombre de threads que les acteurs peuvent utiliser limitera simplement le nombre de jobs qui sont réellement exécutés simultanément. J'ai produit des erreurs d'OOM en générant du travail plus rapidement que les acteurs ne peuvent le faire auparavant, donc vous devez faire attention. –

+2

Je pense qu'un inconvénient de cette approche est qu'elle est globale. Parfois, j'ai différents types de processus que j'ai besoin d'exécuter qui ont différents niveaux d'utilisation des ressources - avec les pools de threads Java, je peux facilement utiliser des pools différents avec des paramètres différents. Avec 'actors.maxPoolSize', je ne peux utiliser qu'un seul nombre pour tous les acteurs, car ils sont tous alimentés par le même pool de threads, non? –

6

Je vous encourage vraiment à jeter un oeil à Akka, une implémentation d'acteur alternatif pour Scala.

http://www.akkasource.org

Akka a déjà une intégration JAX-RS [1] et vous pouvez l'utiliser de concert avec un LoadBalancer [2] pour accélérateur combien d'actions peut être fait en parrallèle:

[1 ] http://doc.akkasource.org/rest [2] http://github.com/jboner/akka/blob/master/akka-patterns/src/main/scala/Patterns.scala

+0

Intéressant, je vais vérifier, merci! –

3

Vous avez vraiment deux problèmes ici.

La première consiste à garder le pool de threads utilisé par les acteurs sous contrôle. Cela peut être fait en définissant la propriété système actors.maxPoolSize.

La seconde est la croissance fulgurante du nombre de tâches soumises au pool. Vous pouvez ou non être concerné par celui-ci, cependant il est tout à fait possible de déclencher des conditions d'échec telles que des erreurs de mémoire insuffisante et dans certains cas des problèmes potentiellement plus subtils en générant trop de tâches trop rapidement.

Chaque thread de travail maintient une file d'attente de tâches. La dequeue est implémentée en tant que tableau que le thread de travail va agrandir dynamiquement jusqu'à une taille maximale. Dans 2.7.x la file d'attente peut grossir elle-même et j'ai vu des erreurs de mémoire en cas de combinaison avec de nombreux threads concurrents. La taille maximale de la file d'attente est plus petite 2.8. La dequeue peut également remplir.

Pour résoudre ce problème, vous devez contrôler le nombre de tâches que vous générez, ce qui signifie probablement une sorte de coordinateur comme indiqué. J'ai rencontré ce problème lorsque les acteurs qui initient un type de pipeline de traitement de données sont beaucoup plus rapides que ceux qui sont plus tard dans le pipeline. Pour contrôler le processus, j'ai généralement les acteurs plus tard dans la chaîne ping les acteurs plus tôt dans la chaîne tous les messages X, et ont les plus tôt dans la chaîne s'arrêter après les messages X et attendre le retour du ping. Vous pouvez également le faire avec un coordinateur plus centralisé.