2016-12-19 2 views
1

J'utilise actuellement un système Acteur akka dans mon code Scala. J'ai un acteur parent et un acteur enfant. Ce que je veux faire est d'initier une liste à l'acteur parent et laisser l'acteur enfant:Variable globale dans le système d'acteur akka dans Scala

i) Générer de nouveaux éléments et les envoyer à l'acteur parent qui les joindra à la liste. ii) Avoir accès aux éléments de la liste à tout moment.

Comment puis-je atteindre la deuxième partie (ii)?

Répondre

-1

Eh bien, j'ai réussi à trouver une solution.

Si vous créez une variable dans l'acteur parent et que vous la transmettez en tant que paramètre de construction à l'acteur enfant, chaque modification de cette variable est visible si vous ne la remplacez pas. Je vais expliquer avec un exemple correct suite à un faux exemple.

class ParentActor(/*constructors here*/) extends Actor{ 
    val list =ListBuffer[Int](1,2) 
    child = new ChildActor(list //+other constructors) 

    list=ListBuffer[Int](1,2,3) // **wrong** child will see list=List(1,2) 
    list+=3   // **right** child will see list=List(1,2,3) as wanted 

}

class ChildActor(list : ListBuffer[Int] /*++ otherconstructors here*/) extends Actor{ 

     list=ListBuffer[Int](1,2,3,4) // **wrong** parent will see list=List(1,2,3) 
     list+=4   // **right** child will see list=List(1,2,3,4) as wanted 

}

+0

Cette solution est un Akka anti-pattern et n'est pas recommandable. Tout d'abord, notez que ListBuffer n'est pas une collection thread-safe. Deuxièmement, même choisir une collection thread-safe violerait la transparence de l'emplacement - comme la sérialisation serait impossible. Plus de lecture ici http://manuel.bernhardt.io/2016/08/02/akka-anti-patterns-shared-mutable-state/ –

1

Vous pouvez choisir un message spécifique auquel le parent peut répondre en divulguant son statut interne. Voir un exemple ci-dessous:

import scala.collection.immutable.Queue 

    class Parent extends Actor { 
    import Parent._ 

    // TODO: start children here 

    override def receive: Receive = receiveElements(Queue.empty[Element]) 

    def receiveElements(acc: Queue[Element]): Receive = { 
     case [email protected] => context.become(receiveElements(acc :+ e)) 
     case GetElements => sender ! acc 
    } 
    } 

    object Parent { 
    case class Element(s: String) 
    case object GetElements 
    } 

Notez que le même comportement est réalisable en gardant une var queue interne au parent au lieu d'utiliser context.become + récursivité. En outre, ne pas concevoir un moyen pour que la file d'attente soit vidée peut potentiellement conduire à OOME.

+0

Le problème est que je souhaite avoir accès à cette liste lors de l'exécution. Je veux que mon acteur enfant reçoive un message "start", exécute une fonction et accède à la liste à l'intérieur de la fonction thiw. Je ne veux pas attendre que le premier message soit traité et ensuite gérer un deuxième message. – Noowada

+1

Dit simplement: impossible. Cela viole tous les principes d'Akka. – Ryan

+0

Question redéfinie: http://stackoverflow.com/questions/41247523/how-to-periodically-check-an-actor-mailbox-and-alter-variables-in-scala – Noowada

3

Vous devez utiliser le passage de message. Le partage de tout type d'état mutable entre deux acteurs viole toutes les garanties offertes par Akka.

Alternativement, vous pouvez partager un Agent entre votre enfant et les acteurs parents, ce qui linéariserait les mises à jour de la liste tout en permettant les lectures synchrones.

+0

J'ai changé myquestion pour être plus représentatif de ce que je souhaitez faire: – Noowada

+0

http://stackoverflow.com/questions/41247523/how-to-periodically-check-an-actor-mailbox-and-alter-variables-in-scala – Noowada