ネストされたdosync呼び出しを作成するとどうなりますか?サブトランザクションは親スコープで完了しますか?親トランザクションが失敗した場合、これらのサブトランザクションは元に戻せますか?
1 に答える
構文の入れ子を意味する場合、答えは、内側が外側のスレッドと同じスレッドで実行されるかどうかに依存しdosync
ます。
Clojure では、dosync
ブロックに入るたびに、このスレッドでまだトランザクションが実行されていなければ、新しいトランザクションが開始されます。これは、実行が単一のスレッドにとどまっている間、内部トランザクションは外部トランザクションに包含されていると言えることを意味します。ただし、 aがdosync
別の 内に構文的にネストされた位置を占有しているdosync
が、たまたま新しいスレッドで起動された場合、それ自体に新しいトランザクションが作成されます。
(うまくいけば)何が起こるかを示す例:
user> (def r (ref 0))
#'user/r
user> (dosync (future (dosync (Thread/sleep 50) (println :foo) (alter r inc)))
(println :bar)
(alter r inc))
:bar
:foo
:foo
1
user> @r
2
「内部」トランザクションは、印刷後に再試行します:foo
。「外側の」トランザクションを再起動する必要はありません。(これが発生した後、r
の履歴チェーンが成長することに注意してください。そのため、「大きな」dosync
フォームが 2 回目に評価された場合、内側dosync
は再試行されません。もちろん、それでも外側のフォームにマージされません。)
ちなみに、Mark Volkmann は Clojure のSoftware Transactional Memoryに関する素晴らしい記事を書いています。この種の詳細について確固たる洞察を得ることに関心のある人には、一読を強くお勧めします。