2013-06-18 51 views
7

有沒有什麼辦法可以調查Clojure的STM交易是否正在重試,並且以什麼比率?可以監視STM的爭用級別嗎?

+0

參見:http://stackoverflow.com/questions/4792197/how-can-i-see-the-number-of-rollbacks-in-my-stm-in-clojure – noahlz

回答

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 

歷史計數並不直接代表爭。相反,它代表爲維護併發讀取而保留的過去值的數量。

歷史記錄的大小受限於minmax值。默認情況下,分別爲010,但創建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塊提交計數(名爲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])) 
相關問題