2013-06-18 2 views

ответ

2

Вы можете наблюдать history count из реф, который будет указывать, что есть конкуренция на нем:

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 

Отсчет истории непосредственно не представляют раздор. Вместо этого он представляет количество прошлых значений, которые поддерживались для обслуживания одновременных чтений.

Размер журнала ограничен min и max значениями. По умолчанию это 0 и 10, соответственно, но вы можете изменить их при создании ref (см. Выше). Так как min-history - 0 по умолчанию, вы обычно не увидите ref-history-count, возвращаете ненулевые значения, если только не существует споров по реф.

Смотреть больше обсуждения history count здесь: https://groups.google.com/forum/?fromgroups#!topic/clojure/n_MKCoa870o

Я не думаю, что есть какой-нибудь способ, предусмотренные clojure.core, соблюдать скорость STM сделок на данный момент. Конечно, вы можете сделать что-то подобное тому, что сделал @Chouser в Его history stress test:

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

т.е. приращение счетчика внутри транзакции. Приращение будет происходить каждый раз при попытке транзакции. Если try-count больше, чем 1, транзакция была повторена.

+0

Никогда не думал используя счет истории, или атомы в пределах txs. Спасибо за предложения! – vemv

2

Вводя имя dosync блоков и совершает COUNTS (времена поименованного dosync преуспело), ​​можно довольно легко следить за раз нитей имеют повторена данную сделку.

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

Учитывая следующий пример ...

(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 вычисляет:

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

Эта дополнительная реализация существенно проще.

;; {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])) 
Смежные вопросы