2014-04-01 12 views
10

Sto appena iniziando a imparare Akka Actors in Scala. La mia comprensione è che i messaggi ricevuti da un attore vengono accodati nella cassetta postale di un attore e elaborati uno alla volta. Elaborando i messaggi uno alla volta, i problemi di concorrenza (condizioni di competizione, deadlock) vengono mitigati.Utilizzo di Futures in Akka Actors

Ma cosa succede se l'attore crea un futuro per eseguire il lavoro associato a un messaggio? Poiché il futuro è asincrono, l'attore potrebbe iniziare a elaborare i successivi messaggi diversi mentre il futuro associato al messaggio precedente è ancora in esecuzione. Questo non creerebbe potenzialmente condizioni di gara? Come si può tranquillamente usare i futures nel metodo receive() di un attore per svolgere attività a lungo termine?

+0

vuoi dire che l'azione associata al futuro opera sulle variabili interne all'attore? allora sì, è una condizione di gara. –

risposta

1

Se è necessario modificare lo stato nei future senza bloccare i messaggi in arrivo, è possibile riconsiderare la riprogettazione del modello di attore. Vorrei introdurre attori separati per ogni attività su cui useresti quei futuri. Dopotutto, il compito principale di un attore è quello di mantenere il suo stato senza lasciarlo sfuggire, fornendo così una concorrenza sicura. Definisci un attore per quei compiti a lungo termine la cui responsabilità è solo quella di prendersene cura.

Invece di prendersi cura dello stato manualmente, si potrebbe prendere in considerazione l'utilizzo di akka's FSM in modo da ottenere un'immagine molto più chiara di ciò che cambia quando. Preferisco presonalmente questo approccio alle variabili brutte quando mi occupo di sistemi più complessi.

16

Il modo più sicuro per utilizzare i future all'interno di un attore è utilizzare sempre lo pipeTo in futuro e inviare il suo risultato come messaggio a un attore (probabilmente lo stesso attore).

import akka.pattern.pipe 

object MyActor { 

    def doItAsynchronously(implicit ec: ExecutionContext): Future[DoItResult] = { 
    /* ... */ 
    } 

} 

class MyActor extends Actor { 

    import MyActor._  
    import context.dispatcher 

    def receive = { 
    case DoIt => 
     doItAsynchronously.pipeTo(self) 
    case DoItResult => 
     // Got a result from doing it 
    } 

} 

Ciò garantisce che non si muta alcun stato all'interno dell'attore.

+2

+1, e nel caso in cui non fosse chiaro da questa risposta, 'doItAsynchronously' dovrebbe * NOT * mutare qualsiasi stato dell'attore. In effetti, se puoi spostare quella funzione su un oggetto associato (o qualsiasi altra cosa che non avrebbe accesso al "questo" dell'attore), sarebbe più facile mantenere la tua onestà al riguardo. –

+0

Buon punto, modifico il mio esempio per renderlo chiaro. – Ryan