4

私はclojure.org/refsでそれを読みました

Ref のすべての読み取りでは、トランザクションの開始点 (その「読み取りポイント」) での「Ref world」の一貫したスナップショットが表示されます。トランザクションには、行った変更が表示されます。これはイントランザクション値と呼ばれます。

ウィキペディアのスナップショット分離へのリンクもあります。これは、トランザクションが開始されると、任意の数の参照の読み取りが互いに一貫していることを意味します。

テストケースを作った...

(def r1 (ref 0))
(def r2 (ref 0))

(defn delay-then-inc-ref [id ref delay]
  (.start 
    (Thread. 
        #((println id " start")
          (Thread/sleep delay)
          (dosync
             (alter ref inc))
             (println id " end")))))

(defn deref-delay-deref [ref1 ref2 delay]
    (.start 
       (Thread. 
          #((println "S start")
            (dosync 
              (let [a @ref2]
                 (Thread/sleep delay)
                 (println "S r1=" @ref1))) ; @ref1 consistent with @ref2 ?
                 (println "S end")))))

*clojure-version*
;=> {:major 1, :minor 3, :incremental 0, :qualifier nil}
(deref-delay-deref r1 r2 2000) 
(delay-then-inc-ref "1" r1 500)
(delay-then-inc-ref "2" r1 1000)
(delay-then-inc-ref "3" r1 1500)

出力は次のとおりです。

S start
1 start
2 start
3 start
1 end
2 end
3 end
r1 = 3
S end
nil

not の値は、 r1 = 3ref1の deref でが 3 つのトランザクションが発生したに r1 の値を選択してr1 = 0いることを示唆しています。deref-delay-derefsleepdelay-then-inc-ref

ensure特定のトランザクション中に他のトランザクションによる参照への更新を防ぐことについては知っていますが、ここでは当てはまらないと思います。ref1トランザクションの開始と一致する値が表示される限り、変更されても気にしません。

この動作は、上記の参照ドキュメントにどのように適合しますか?

4

1 に答える 1

1

ref に何らかの履歴がある場合、期待どおりに動作することが判明したため、ref 宣言を変更して a を追加し、:min-history両方の ref を示されているように設定すると、動作するように見えます....

(def r1 (ref 0 :min-history 5))
(def r2 (ref 0 :min-history 5))

(dosync
 (ref-set r1 0)
 (ref-set r2 0))

出力は次のとおりです。

S start
1 start
1 end
2 start
2 end
3 start
3 end
S r1= 0
S end
nil

ここを読むと、何が起こっているかは明らかです。トランザクション開始前の参照履歴にエントリがないため、読み取りトランザクションが再開されます。確認するために、さらにログを追加しました。

(defn deref-delay-deref [ref1 ref2 delay]
    (.start 
       (Thread. 
          #((println "S start")
            (dosync
              (println "transaction starting")
              (let [a @ref2]
                 (Thread/sleep delay)
                 (println "S r1=" @ref1))) ; should be consistent with @ref2
            (println "S end")))))

履歴変更なしの出力:

S start
transaction starting
1 start
2 start
3 start
1 end
2 end
3 end
transaction starting
S r1= 3
S end

そして歴史の改造で:

S start
transaction starting
1 start
2 start
3 start
1 end
2 end
3 end
S r1= 0
S end
nil

更新:上記の私の回答は、テスト ケースの人為的な性質のために気を散らすものであることがわかりました。実際の使用では、トランザクションが再起動できるように記述されている必要があるため、トランザクションが再起動するかどうかは問題ではありません。ランタイムは、履歴の有無にかかわらず読み取り専用トランザクションが完了するかどうかについて保証しません。むしろ、トランザクションの世界を完成させるために必要なことは何でも行うことができ、トランザクション コードはこれを念頭に置いて記述しなければなりません。詳しい議論はこちら

以上、参考までに残しておきます。

于 2012-04-16T17:42:25.237 に答える