La mia descrizione del modello dell'attore è corretta?


13

Se ho capito, il modello dell'attore è proprio come il modello a oggetti, ma con alcune differenze:

  1. OGNI oggetto genera il proprio thread separato e non è un problema anche quando hai migliaia di oggetti.
  2. Gli attori non interagiscono chiamando le funzioni e ottenendo valori di ritorno ma invece inviando e ricevendo messaggi.
  3. Se non violi quel modello, la tua app utilizzerà la concorrenza al massimo della sua potenza senza rischi di condizioni di gara.
  4. Tutto ciò che puoi fare in OO puoi fare usando gli attori, ma meglio, il problema è che tutto ciò che abbiamo codificato negli ultimi anni era basato su OO - ma una transizione è imminente.

Quindi, per esempio, supponiamo che io debba definire la classe / attore vettoriale 3d, creare due istanze e chiamare un'operazione somma su di essi.

ORIENTATO AGLI OGGETTI:

class V3d {
   constructor V3d(x,y,z) //bla
   float x,y,z;
   function sum(V3d b) 
   { 
      return V3d(x+b.x,y+b.y,z+b.z); 
   }
}

//using:
mySum = V3d(1,2,3).sum(V3d(3,2,1)) //creates 2 instances, sum, returns instantly
drawPoint(mySum) //uses the result

MODELLO ATTORE:

actor V3d 
{
    constructor V3d(x,y,z) //bla
    float x,y,z;
    loop 
    {
       receive 'sum',b:V3d :
           send(caller,'sumResult',V3d(x+b.x,y+b.y,z+b.z))
    }
 }

//using:
send(V3d(1,2,3),'sum',V3d(3,2,1)) //creates 2 instances, send to the first one a request to sum with the second one

loop 
{
   receive 'sumResult',result:
      drawPoint(result) //receives result and draws it
}

È così? O mi sbaglio completamente?


Gli attori leggeri o i microagenti o i componenti del flusso di dati non utilizzano necessariamente il proprio thread. :-) Controlla i seguenti termini: programmazione basata sull'attore, programmazione basata sull'agente, programmazione basata sul flusso di dati. Sono molto simili, ma hanno vincoli diversi. Ohh, lo farò come una domanda ;-)
inf3rno

Risposte:


12

La risposta breve è no, non è corretta.

  1. inizia ragionevolmente corretto (ogni attore almeno potenzialmente viene eseguito come thread indipendente), ma poi esce ampiamente dalle rotaie. Non c'è nulla nel modello che faccia funzionare bene molti thread, dipende dall'implementazione. Al massimo, la facilità di creazione di molti thread mette sotto pressione l'implementazione per fornire un threading efficiente. Almeno per quanto riguarda il modello, qualsiasi somiglianza tra attori e oggetti è per lo più casuale. "Oggetto" comporta implicazioni abbastanza specifiche su come combinare codice e dati. Un attore coinvolge generalmente sia il codice che i dati, ma implica poco sul modo in cui sono combinati (a parte il fatto che i soli dati visibili al mondo esterno sono i messaggi).

  2. Il solito modo di descrivere l'interazione è come l'invio di messaggi, sì. Non ho una citazione a portata di mano, ma qualcuno ha dimostrato molto tempo fa che meccanismi come le funzioni virtuali C ++ sono isomorfi per l'invio di messaggi (poiché le funzioni virtuali sono normalmente implementate, stai usando un offset in una vtable - ma se tu inviato invece un offset in una tabella di messaggi, l'effetto sarebbe lo stesso).

  3. Non è così semplice. Se riesci a trovarne una copia, Henry Baker (con qualcun altro il cui nome non ricordo in questo momento) ha scritto un documento sulle regole necessarie per la coerenza dei dati nel modello Actor.

  4. "Meglio" è altamente soggettivo nella migliore delle ipotesi. Alcuni problemi sono di natura molto parallela e coinvolgono davvero un gran numero di entità essenzialmente autonome, con un'interazione minima principalmente asincrona. In questo caso, il modello dell'attore può davvero funzionare molto bene. Per altri problemi, non è proprio così. Alcuni problemi sono quasi interamente di natura seriale. Altri possono essere eseguiti in parallelo, ma richiedono comunque una stretta sincronizzazione tra quelle azioni (ad esempio, essenzialmente una modalità simile a SIMD, in cui si esegue un'istruzione alla volta, ma ciascuna istruzione agisce su un gran numero di elementi di dati). È certamente possibile risolvere entrambi questi tipi di problemi usando il modello di attore - ma per tali problemi, spesso comporta una discreta quantità di lavoro extra per un guadagno scarso o nullo in cambio.


Non c'è relazione tra il numero di attori e il numero di thread; ciò che il modello di attore garantisce è che una determinata istanza sarà gestita da un singolo thread alla volta, quindi i tuoi attori sono già thread-safe e non è necessario utilizzare al loro interno strategie di sincronizzazione e blocco.
Rob Crawford,

@RobCrawford: questo è un modo (abbastanza banale) per garantire la coerenza dei dati nel modello Actor. Il documento Hewitt / Baker copre più possibilità, come copie multiple di un attore che corre in thread separati (hmm ... guardando la mia risposta, mi chiedo se non potrei onestamente ricordare il nome di Carl Hewitt in quel momento, o era essere ironico quando l'ho scritto).
Jerry Coffin,

L' asincronicità del messaggio che passa non è forse un elemento essenziale del modello? Ciò impedirebbe sicuramente che sia isomorfo con chiamate di funzione virtuali, che sono di natura sincrona. O la distinzione è irrilevante da una certa prospettiva?
Boycy,

2

Riguardo a 1: ho lavorato con un'applicazione modellata come attore a thread singolo (ish), quindi è del tutto possibile ignorare il grande numero di thread suggerito. AFAIK, i thread non sono affatto oggetti leggeri, quindi probabilmente non è desiderabile averne uno per ogni attore, a seconda di quanti attori stai usando.

Per quanto riguarda 3: sono abbastanza sicuro che le condizioni di gara possano verificarsi nei sistemi modellati da attori semplicemente a causa della logica di programmazione?

Riguardo a 4: definire 'migliore'? La mia esperienza è stata che la logica asincrona può essere molto più difficile da leggere rispetto alle cose sincrone. ad esempio, nel tuo esempio sopra, non sai quale operazione è responsabile di quale risultato, quindi c'è un ulteriore monitoraggio del messaggio da fare. Una volta che questo viene aggiunto e altri messaggi in entrata e in uscita sono inclusi nella logica, l'intento del codice viene distribuito su diverse funzioni di invio / ricezione.

Detto questo, sono un grande fan dell'uso del modello di attore per i livelli superiori di un'applicazione. Può semplificare il disaccoppiamento, poiché l'aggiunta di dipendenze è un po 'più difficile dell'aggiunta di una funzione. Inoltre non ho molta esperienza con un livello superiore rispetto ai linguaggi Java e altri paradigmi potrebbero supportare l'asincrono in un modo più fondamentale.


Riguardo al n. 1: "thread" può riferirsi a molte cose. I thread del sistema operativo sono in genere abbastanza pesanti, veri, ma esistono runtime linguistici che gestiscono internamente centinaia, migliaia, persino milioni di "thread" di esecuzione all'interno di un numero limitato di thread del sistema operativo. In alcune implementazioni, tali modelli sembrano scalare fino a dozzine di core (ho visto affermazioni che le recenti versioni di GHC funzionano bene con 32 core).
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.