2011-09-18 24 views
9

Se voglio mantenere un contatore globale (ad esempio per contare il numero di richieste in entrata su più thread), il modo migliore per fare in java sarebbe utilizzare un int volatile. Supponendo che venga usato il clojure, c'è un modo migliore (migliore rendimento) di fare?contatore sincronizzato in clojure

risposta

13

farei questo con un atom in Clojure:

(def counter (atom 0N)) 

;; increment the counter 
(swap! counter inc) 

;; read the counter 
@counter 
=> 1 

Questo è totalmente thread-safe, e sorprendentemente elevate prestazioni. Inoltre, dato che utilizza abitrary precisione manipolazione numerica di Clojure, non è vulnerabile a integer overflow in modo che un int volatile può essere .....

+0

sarebbe meglio fornire un throughput quindi utilizzando un int volatili? se sì, qualsiasi intuizione sul perché/come è meglio. – 142857

+1

Un atomo sarebbe un po 'più lento di un int volatile. Ma a meno che non contiate milioni di eventi al secondo, la differenza non sarebbe abbastanza grande da notare. E a quel livello di throughput, un int volatile traboccherebbe in meno di un'ora ...... – mikera

+3

Su Clojure 1.3, può overflow: '(scambia (atom 9223372036854775807) inc)' lancia un'eccezione di overflow. La correzione consiste nell'utilizzare BigInts: '(swap! (Atom 9223372036854775807N) inc)' o la funzione di promozione automatica 'inc'' –

7

Definire un contatore globale come agent

(def counter (agent 0)) 

per aumentare il valore contenuto nel agente che si send una funzione (in questo caso inc) all'agente:

(send counter inc) 

per leggere il valore corrente è possibile utilizzare deref o @ lettore macro:

@counter ;; same as (deref counter) 

Gli agenti sono solo uno dei diversi tipi di riferimento disponibili. Si può leggere di più su queste cose sul sito Clojure: