Có cách nào để thăm dò xem liệu các giao dịch STM của Clojure có đang được thử lại hay không và ở mức nào?Có thể theo dõi mức độ tranh chấp của STM không?
Trả lời
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ị min
và max
. Theo mặc định, những người này tương ứng là 0
và 10
nhưng bạn có thể thay đổi chúng khi tạo ref
(xem bên trên). Vì min-history
là 0
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.
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
Bằng việc giới thiệu tên dosync khối và phạ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}}, ...}
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]))
Xem thêm: http://stackoverflow.com/questions/4792197/how-can-i-see-the-number-of-rollbacks-in-my-stm-in-clojure – noahlz