Esiste un modo per sondare se le transazioni STM di Clojure vengono ripetute e in quale misura?È possibile monitorare il livello di contesa di STM?
risposta
È 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.
mai pensato di utilizzando il conteggio storico o gli atomi all'interno di txs. Grazie per i suggerimenti! – vemv
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}}, ...}
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]))
Consulta anche: http://stackoverflow.com/questions/4792197/how-can-i-see-the-number-of-rollbacks-in-my-stm-in-clojure – noahlz