2013-06-18 27 views

Odpowiedz

2

Można obserwować history count o sygn które wskazują, że istnieje spór na nim:

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 

Hrabia historia nie bezpośrednio reprezentować tezę. Zamiast tego przedstawia liczbę przeszłych wartości, które zostały utrzymane w celu obsługi jednoczesnych odczytów.

Wielkość historii jest ograniczona wartościami min i max. Domyślnie są to odpowiednio 0 i 10, ale można je zmienić podczas tworzenia ref (patrz wyżej). Ponieważ min-history jest domyślnie 0, zwykle nie widzisz ref-history-count zwracania wartości niezerowych, chyba że istnieje niezgodność na ref.

Zobacz więcej dyskusji na history count tutaj: https://groups.google.com/forum/?fromgroups#!topic/clojure/n_MKCoa870o

Nie sądzę, istnieje jakikolwiek sposób, pod warunkiem przez clojure.core, aby obserwować szybkość transakcji STM w tej chwili. Można oczywiście zrobić coś podobnego do tego, co miało miejsce w @Chouser Jego history stress test:

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

czyli przyrost wartości licznika wewnątrz transakcji. Przyrost będzie dokonywany za każdym razem, gdy transakcja zostanie wypróbowana. Jeśli try-count jest większy niż 1, transakcja została ponowiona.

+0

Nigdy nie myślał o za pomocą liczby historii lub atomów w txs. Dzięki za sugestie! – vemv

2

Wprowadzając nazwie dosync bloków i popełnić policzy (czasy nazwany dosync udało), można łatwo śledzić czasów nici zostały ponowione daną transakcję.

(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)))) 

Biorąc pod uwagę następujący przykład ...

(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 ocenia się:

;; {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

Ta dodatkowa implementacja jest znacznie prostsze.

;; {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]))