6
votes

Comprendre la filetage des acteurs dans Scala

On m'a dit que les acteurs (Scala) n'exécutent jamais deux opérations en même temps, ce qui suggère que la méthode est intrinsèquement synchronisée. Je sais qu'une opération longue dans une méthode d'acte peut provoquer des problèmes de blocage, et je suppose que l'accès à la file d'attente de messages doit être synchronisé d'une manière ou d'une autre ... mais ...

Qu'est-ce qui a été suggéré est qu'un acteur recevant des messages qui lui disent d'incrémenter un compteur interne incrémenterait le compteur de manière threadsafe. Qu'augmente deux messages de mise à jour ne seraient traités simultanément, et aucun message à deux, aucun message ne pourrait tenter de mettre à jour le compteur en même temps.

Un attribut de compteur dans un acteur ressemble à un "état partagé".

Est-il vraiment vrai qu'une telle opération serait complètement threadsafe? Si oui, comment un acteur utilise-t-il de multiples machines de base de manière efficace? Comment un acteur est-il multi-fileté du tout?

Sinon, qu'est-ce qui est un moyen idiomatique approprié de compter des messages de manière threadsafe sans avoir besoin d'une variable synchronisée / volatile?


0 commentaires

3 Réponses :


6
votes

"Un acteur" n'est pas multithread, mais un système acteur est généralement. Chaque acteur n'existe qu'une seule action à la fois, mais lorsqu'il y a plusieurs acteurs, chacun peut fonctionner sur son état encapsulé respectif en parallèle. Un attribut de compteur n'est pas partage d'état mutable partagé si elle n'est pas partagée entre les acteurs .

Si votre question concerne la mise en œuvre du système Acteur, cela varie et est généralement configurable, c'est-à-dire des acteurs Scala par défaut, peuvent être configurés pour exécuter une piscine à filetage unique ou sur une piscine de fil ou à l'aide de tâches Java Forkjoin. Je trouve la source scala.actors très lisible, alors je recommande de jeter un oeil si vous voulez comprendre ce qui se passe.


1 commentaires

+1 pour le pointeur sur le code source SCALA. Il montre bien le concept.



2
votes

Vous pouvez utiliser un acteur séparé pour faire le comptage. Lorsqu'un acteur reçoit un message, cela pourrait déclencher un message à un acteur de comptage (singleton). De cette façon, vous pourriez avoir plusieurs acteurs de travailleurs et enregistrer toujours des messages.

akka a quelque chose appelé agents qui pourrait être utile dans ce contexte. xxx

http://doc.akka.io/docs/akka/2.0.2/scala/agents.html


1 commentaires

Un agent est conçu pour ce boîtier d'utilisation. En termes de threadness et de synchronisation, ils fonctionnent comme des acteurs des écrivies et d'Atomicx pour des lectures.



8
votes

Le modèle Acteur peut être utilisé pour isoler l'état mutable du monde extérieur. Lorsque vous avez un état mutable (par exemple, un registre global des identifiants attribués à plusieurs processus concurrents), vous pouvez envelopper cet état mutable à l'intérieur d'un acteur et rendre les clients communiquant avec l'acteur par le passage de message. De cette façon, seul l'acteur accède directement à l'état mutable, et comme vous le dites, la file d'attente des messages du client doit être lu et traité un seul par un. Il est important que les messages soient immuables.

Pour éviter la file d'attente, il est important que le traitement du message ( réagit , recevoir , etc.) soit court que possible. Les tâches à long terme doivent être transmises à un autre acteur: xxx

quelques alternatives dans le processus:

  • c envoie (s, résultat) retour à A qui en avant à S
  • A conserve un mappage acorref c => (expéditeur S, message M) donc au cas où il voit c échouer , il peut réessayer le traitement M avec un nouvel acteur.

    pour récapituler, un acteur est multi-fileté dans la mesure où plusieurs clients peuvent l'envoyer plusieurs messages à partir de divers threads, et il est garanti que l'acteur traitera toutes ces messages en série (bien que la commande puisse Soyez sujet à diverses contraintes non trop strictes).

    Notez que, tandis que le de l'acteur réagit peut être exécuté sur divers threads , dans un seul moment donné, il est exécuté sur un seul fil donné uniquement (vous pouvez imaginer cela L'acteur saute du fil à filer lorsque le planificateur voit en forme, mais il s'agit d'un détail technique). Remarque: L'état interne n'a toujours pas besoin de syncronisation, car les acteurs Garantie arrive - avant la sémantique entre les messages de traitement.

    Le parallélisme est obtenu en ayant plusieurs acteurs travaillant en parallèle, formant généralement hiérarchies superviseur ou Balance de la charge de travail .

    Notez que si tout ce dont vous avez besoin est des calculs simultanés / asynchrones, mais vous n'avez pas ou ne pouvez pas vous débarrasser de l'état global, futur s sont un mieux composer et concept plus facile.


2 commentaires

Bonne réponse. J'ajouterais que lorsque les réactions d'un acteur peuvent être exécutées sur différents threads (et que normalement sont soumis à des problèmes d'accès à la mémoire), vous n'avez réellement pas besoin de synchroniser l'accès à l'état de l'acteur. En effet, le cadre de l'acteur fait déjà déjà avant d'exécuter un acteur. Voir Content que cela aide. Régis: Merci, mis à jour le texte à être plus précis.