2015-10-28 10 views
7

Questo è uno scenario comune in cui mi imbatto, in cui ho due (o più) attori che ottengono alcuni dati in modo asincrono, e quindi ho bisogno di fare un'operazione quando sono tutti finiti.Akka.net in attesa di più pezzi di dati

Qual è lo schema comune per farlo?

Ecco un esempio semplificato.

public MasterActor : ReceiveActor 
{ 
    public MasterActor() 
    { 
      Initialize(); 
    } 

    public void Initiaize() 
    { 
     Receive<DoSomeWork>(_ => 
     { 
       var actor1 = Context.ActorOf(Props.Create(() => new Actor1()); 
       var actor2 = Context.ActorOf(Props.Create(() => new Actor2()); 

       // pretend these actors send responses to their senders 
       // for sake of example each of these methods take between 1 and 3 seconds 
       actor1.Tell(new GetActor1Data()); 
       actor2.Tell(new GetActor2Data()); 
     }); 

     Receive<Actor1Response>(m => 
     { 
      //actor 1 has finished it's work 
     }); 

     Receive<Actor2Response>(m => 
     { 
      //actor 2 has finished it's work 
     }); 
    } 
} 

Per calci fuori questo mando il MasterActor un messaggio DoSomeWork.

Qual è il modo comune di eseguire un'operazione quando ho sia un Actor1Response sia un Actor2Response.

Non voglio davvero avere la logica in ogni gestore di ricezione che controlla se l'altro è finito o qualcosa del genere. Immagino cosa sto pensando a qualcosa di simile a un metodo Task.WaitAll().

Sto semplicemente attaccando il problema nel modo sbagliato? Devo riscrivere gli attori in un modo diverso?

Qualsiasi schema o soluzione comune sarebbe fantastico.

risposta

3

La soluzione comune è quella di collegare un tipo di ID di correlazione condivisa da entrambi i messaggi di richiesta e di risposta - poiché l'attore elabora i messaggi in modo sincrono, questo potrebbe essere il contatore int/long non selezionato.

È sufficiente archiviare gli ID di correlazione in una struttura di dati (diciamo set) all'interno del chiamante e quando viene ricevuta una risposta, rimuoverlo dall'ID di correlazione. WaitAll termina sostanzialmente quando l'impostazione è vuota o si verifica un timeout.

È possibile impostare il timeout utilizzando Context.SetReceiveTimeout(timeout), in questo modo l'attore invierà un metodo ReceiveTimeout a se stesso dopo che non ha ricevuto alcun messaggio per qualche tempo.

Questo comportamento è piuttosto generico e può essere facilmente risolto.

2

Il modo più semplice per eseguire questa operazione consiste nell'incrementare un conteggio "voto" sul master quando risponde ogni bambino. Quando voti == il numero dei bambini, hai finito.

È possibile estenderlo in modo da contare solo il primo messaggio di ciascun figlio o un messaggio specifico di ogni bambino, ma tutto si riduce al conteggio alla fine.