2013-06-18 31 views

Trả lời

2

Bạn có thể quan sát history count của một ref đó sẽ chỉ ra rằng có tranh cãi về nó:

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 

Số đếm lịch sử không trực tiếp đại diện tranh chấp. Thay vào đó nó đại diện cho số lượng các giá trị trong quá khứ đã được duy trì để phục vụ đọc đồng thời.

Kích thước lịch sử bị giới hạn bởi các giá trị minmax. Theo mặc định, những người này tương ứng là 010 nhưng bạn có thể thay đổi chúng khi tạo ref (xem bên trên). Vì min-history0 theo mặc định, bạn sẽ không thường thấy ref-history-count trả lại giá trị khác 0, trừ khi có tranh chấp trên ref.

Xem thảo luận thêm về history count đây: https://groups.google.com/forum/?fromgroups#!topic/clojure/n_MKCoa870o

Tôi không nghĩ có bất kỳ cách nào, được cung cấp bởi clojure.core, để quan sát tỷ lệ giao dịch STM vào lúc này. Bạn có thể tất nhiên làm một cái gì đó tương tự như những gì đã làm trong @Chouser history stress test mình:

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

ví dụ: tăng số đếm bên trong giao dịch. Sự gia tăng sẽ xảy ra mỗi lần giao dịch được thử. Nếu try-count lớn hơn 1, giao dịch đã được thử lại.

+0

Chưa bao giờ nghĩ đến việc sử dụng số lượng lịch sử hoặc các nguyên tử trong txs. Cảm ơn các đề xuất! – vemv

2

Bằng việc giới thiệu tên dosync khốiphạm tội (thời gian một dosync tên đã thành công), người ta có thể khá dễ dàng theo dõi các lần đề đã thử lại một giao dịch nhất định.

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

Với ví dụ sau ...

(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 đánh giá để:

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

thực hiện bổ sung này là đơn giản hơn đáng kể.

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