2012-02-03 5 views

risposta

37

I riferimenti sono per lo stato che deve essere sincronizzato tra i thread. Se hai bisogno di tenere traccia di un sacco di cose diverse e a volte dovrai fare operazioni che scrivano su più cose contemporaneamente, usa i riferimenti. Ogni volta che si hanno più diversi stati di stato, l'uso di ref non è una cattiva idea.

Gli atomi sono per stato indipendente che deve essere sincronizzato tra i thread. Se non avrai mai bisogno di cambiare lo stato dell'atomo e qualsiasi altra cosa allo stesso tempo, usare at atom è sicuro (in particolare, se c'è solo un pezzo di stato nell'intero programma, puoi metterlo in un atomo) . Come esempio non banale, se stai cercando di memorizzare nella cache i valori di ritorno di una funzione (ad esempio memorizzalo), l'utilizzo di un atomo è probabilmente sicuro: lo stato è invisibile a qualsiasi cosa al di fuori della funzione, quindi non devi preoccuparti su un cambio di stato all'interno della funzione che incasina tutto.

Il punto principale degli agenti è che funzionano in una filettatura diversa. Puoi ottenere il valore dell'agente e dirgli di applicare una funzione al suo valore, ma non sai quando verrà eseguita la funzione o quale valore verrà applicato alla funzione.

Vars sono per quando è necessario memorizzare qualcosa su una base per-thread. Se hai un programma multi-thread e ogni thread ha bisogno del suo stato privato, mettilo in una var.

Per quanto riguarda gli esempi del mondo reale, se fornisci un esempio di ciò che stai cercando di fare, possiamo dirti cosa usare.

147

mi raccomando "The Joy of Clojure" o "programmazione Clojure" per una vera risposta a questa domanda, posso riprodurre una breve snip-it delle motivazioni per ciascuna:

inizio guardando this video on the notion of Identity e/oppure studying here.

  • Refs sono per coordinato sincrono l'accesso a "molte identità".
  • Gli atomi sono per Uncoordinated syncronous accesso a una singola identità.
  • Gli agenti sono per Uncoordinated asynchronous accesso a una singola identità.
  • Vars sono per il thread locale identità isolate con un valore predefinito condiviso.

Coordinated accesso viene utilizzato quando due identità deve cambiare insieme, l'esempio classico si muove denaro da un conto bancario ad un altro, è necessario spostare sia completamente o per niente.

Uncoordinated L'accesso è utilizzato quando è necessario aggiornare solo un'identità, questo è un caso molto comune.

Synchronous L'accesso viene utilizzato quando si prevede che la chiamata attenda fino a quando tutte le identità si sono risolte prima di continuare.

Asynchronous l'accesso è "fire and forget" e consente all'Identity di raggiungere il suo nuovo stato nel proprio tempo.

+0

In accesso coordinato, se voglio unico cambiamento 'stato-a' , ma si riferisce a 'state-b' nel fare ciò, ho ancora bisogno di un' ref' corretto? Quindi non sta cambiando più cose, ma si riferisce a più cose mentre si cambia uno di loro? –

+0

Sì, sembra che tu capisca correttamente che stato-a e stato-b devono essere entrambi ref Se vuoi che il nuovo valore in stato-a sia basato su una combinazione coerente dei valori in a e b. È necessario che il nuovo valore sia stato calcolato in un contesto in cui stato-a e stato-b sono coerenti tra loro. Quando sono entrambi i ref, se b cambia a metà strada, la transazione verrà riavviata e utilizzerà i nuovi valori di a e b. considera l'utilizzo della funzione 'ensure': http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/ensure per renderlo esplicito e più efficiente. –

+3

Forse una spiegazione di cosa è stato isolato con i metodi di default condivisi per completare la risposta? –

27

Quando ho letto su questi tipi, ho anche faticato a capire dove avrei potuto o dovuto utilizzare ognuno in modo ecco la mia semplice risposta inglese:

Utilizzare una var quando i dati non cambieranno. Ciò accade ogni volta che si utilizza def o la maggior parte delle funzioni che iniziano con def come defn.

Utilizzare un atomo quando si modifica un singolo elemento. Un esempio potrebbe essere un contatore o un vettore a cui si desidera aggiungere elementi.

Utilizzare un riferimento quando si hanno due o più cose che devono cambiare allo stesso tempo. Pensa a "transazioni di database" se hai dimestichezza. L'esempio canonico di questo è il trasferimento di denaro da un account a un altro. Ogni account può essere memorizzato in un ref in modo che le modifiche possano apparire atomiche.

Utilizzare un agente quando si desidera che qualcosa cambi, ma non importa quando. Questo potrebbe essere un lungo calcolo o scrivere qualcosa su un file o un socket. Si noti che con quest'ultimo si dovrebbe usare send-off.

Nota: apprezzo che c'è molto di più in ognuno di questi, ma si spera che questo dovrebbe darvi un punto di partenza.

+0

Grazie mille per la tua chiara risposta :-) Aiuta un novizio Clojure come me parecchio. – gosukiwi

+0

Buono! Grazie... –

16

Ho scritto un articolo con riepilogo sulla differenza tra loro e aiuta a scegliere quando utilizzare quale.

Share state - when use vars, atoms, agents and refs?

spero che aiuterà le persone in cerca risposte in quell'argomento.

Alcuni collegamento dal articolo dopo suggerimento @tunaci:

Vars

Vars sono globali per ogni thread.

Non modificare i vars dopo la creazione. È tecnicamente possibile, ma è una cattiva idea per molte ragioni.

Atomi

condividere l'accesso a stato mutevole per ogni thread. La modifica avviene in modo sincrono. Riprovare quando altri thread cambiano lo stato durante l'esecuzione.

Non usare le funzioni e le funzioni non idempotenti con molto tempo di esecuzione

Agenzia

condividere l'accesso a stato mutevole per ogni thread. La modifica avviene in modo asincrono.

arbitri

Refs funziona in modo simile alle transazioni di database. Scrivi e leggi protetto in dosync. Puoi operare su molti refs sicuri nella transazione.

E diagramma di flusso quando l'uso del quale: flowchart

Si prega di guardare l'immagine sul sito, perché alcuni aggiornamenti sono sempre possibili.

E 'complessa e una lunga argomento per dare risposta completa senza copia & articolo passato, quindi per favore mi perdoni i reindirizzare l'utente al sito :)