2013-06-18 11 views

risposta

2

È possibile osservare la history count di un ref che indicano che non v'è contesa su di esso:

user=> (def my-ref (ref 0 :min-history 1)) 
#'user/my-ref 
user=> (ref-history-count my-ref) 
0 
user=> (dosync (alter my-ref inc)) 
1 
user=> (ref-history-count my-ref) 
1 

Il conteggio storia non rappresenta direttamente contesa. Invece rappresenta il numero di valori passati che sono stati mantenuti per servire letture concorrenti.

La dimensione della cronologia è limitata dai valori min e max. Per impostazione predefinita, sono 0 e 10, ma è possibile cambiarli quando si crea lo ref (vedere sopra). Dal momento che min-history è 0 per impostazione predefinita, non sarà in genere possibile visualizzare valori non nulli pari a ref-history-count, a meno che non vi sia conflitto sul riferimento.

Tutte discussione sul history count qui: https://groups.google.com/forum/?fromgroups#!topic/clojure/n_MKCoa870o

non credo che ci sia alcun modo, fornito da clojure.core, per osservare il tasso delle operazioni di STM in questo momento. Ovviamente si può fare qualcosa di simile a quello che ha fatto nella sua @Chouser history stress test:

(dosync 
    (swap! try-count inc) 
    ...) 

vale a dire incrementare un contatore all'interno della transazione. L'incremento avverrà ogni volta che viene tentata la transazione. Se try-count è maggiore di 1, la transazione è stata ritentata.

+0

mai pensato di utilizzando il conteggio storico o gli atomi all'interno di txs. Grazie per i suggerimenti! – vemv

2

Introducendo nome dosync blocchi e commettere conta (i tempi di un dosync nome è riuscito), si può facilmente tenere traccia dei tempi di discussioni hanno ritentato una determinata operazione.

(def ^{:doc "ThreadLocal<Map<TxName, Map<CommitNumber, TriesCount>>>"} 
    local-tries (let [l (ThreadLocal.)] 
       (.set l {}) 
       l)) 

(def ^{:doc "Map<TxName, Int>"} 
    commit-number (ref {})) 

(def history ^{:doc "Map<ThreadId, Map<TxName, Map<CommitNumber, TriesCount>>>"} 
    (atom {})) 

(defn report [_ thread-id tries] 
    (swap! history assoc thread-id tries)) 

(def reporter (agent nil)) 

(defmacro dosync [tx-name & body] 
    `(clojure.core/dosync 
    (let [cno# (@commit-number ~tx-name 0) 
      tries# (update-in (.get local-tries) [~tx-name] update-in [cno#] (fnil inc 0))] 
     (.set local-tries tries#) 
     (send reporter report (.getId (Thread/currentThread)) tries#)) 
    [email protected] 
    (alter commit-number update-in [~tx-name] (fnil inc 0)))) 

Dato il seguente esempio ...

(def foo (ref {})) 

(def bar (ref {})) 

(defn x [] 
    (dosync :x ;; `:x`: the tx-name. 
      (let [r (rand-int 2)] 
      (alter foo assoc r (rand)) 
      (Thread/sleep (rand-int 400)) 
      (alter bar assoc (rand-int 2) (@foo r))))) 

(dotimes [i 4] 
    (future 
    (dotimes [i 10] 
    (x)))) 

... @history viene valutato come:

;; {thread-id {tx-name {commit-number tries-count}}} 
{40 {:x {3 1, 2 4, 1 3, 0 1}}, 39 {:x {2 1, 1 3, 0 1}}, ...} 
0

Questa ulteriore implementazione è sostanzialmente più semplice.

;; {thread-id retries-of-latest-tx} 
(def tries (atom {})) 

;; The max amount of tries any thread has performed 
(def max-tries (atom 0)) 

(def ninc (fnil inc 0)) 

(def reporter (agent nil)) 

(defn report [_ tid] 
    (swap! max-tries #(max % (get @tries tid 0))) 
    (swap! tries update-in [tid] (constantly 0))) 

(defmacro dosync [& body] 
    `(clojure.core/dosync 
    (swap! tries update-in [(.getId (Thread/currentThread))] ninc) 
    (commute commit-id inc) 
    (send reporter report (.getId (Thread/currentThread))) 
    [email protected]))