2017-06-12 72 views
2

當我要去swap!有條件的一個原子的值時,應該將條件包裝爲swap!還是應該是函數swap!調用的一部分?我應該在我的交換內部還是外部運行支票!功能?

(import '(java.time Instant)) 

(def not-nil? (comp not nil?)) 

(defonce users (atom { 
    "example user 1" {:ts (Instant/now)} 
    "example user 2" {:ts (Instant/now)} 
})) 

(defn update-ts [id] 
    (if (not-nil? (get @users id)) 
    (swap! users assoc-in [id :ts] (Instant/now)))) 

在上面的例子,我做的做swap!之前用戶的存在性檢查。但是,在檢查之後但在swap!之前,用戶是否可以從users中刪除?那麼,將檢查放在由swap!運行的函數內更安全嗎?

(defn update-ts [id] 
    (swap! users (fn [users] 
        (if (not-nil? (get users id)) 
         (assoc-in users [id :ts] (Instant/now)) 
         users)))) 
+0

我認爲這個條件應該包含swap!,調試的時候也很容易。 –

+0

@ErtuğrulÇetin這是我在我的原始代碼中看到的自然本能。但我不希望原子的狀態在檢查和這個特定的'swap!'之間改變。 – DynamiteReed

+0

如果您不認爲將函數中的驗證傳遞給'swap!'是很自然的,那麼您可以考慮使用驗證函數來配置原子。 –

回答

7

但是不能用戶在檢查後但之前swap!從用戶刪除?那麼,將檢查放在由swap!運行的函數內更安全嗎?

是的,完全正確。你永遠不應該做出關於如何從原子上的一個swap!內部的任何位置發生變異的決定。由於swap!是唯一保證爲原子的操作,所以每當你做其他事情時(即從swap!的外部做出關於原子的決定),都會引入競爭條件。

3

但是用戶在檢查後不能刪除用戶,而是在交換前刪除 !那麼,將檢查放在由swap!運行的 函數中是否更安全?

正如amalloy所說,如果你需要它是bulletproot你必須把not-null?檢查放在swap函數中。

但是,請記住,您的團隊正在編寫程序的其餘部分。因此,你有很多的外界信息是可以簡化您的決定:

  • 如果你永遠只能有一個線程(最喜歡的節目),你永遠不必擔心競爭條件。

  • 如果您有2個或更多個線程,也許您永遠不會從地圖中刪除條目(它只會累積:ts值)。那麼你也不需要擔心衝突。

  • 如果你的函數比上面的簡單的例子更復雜,你不妨用一個(dosync ...)形式來包裝,而不是在一個單一的swap功能shoehorning一切多個步驟。

在第三種情況下,將​​替換爲ref。一個例子是:

(defonce users (ref {...})) ; ***** must us a ref here ***** 
(dosync 
    (if (not-nil? (get @users id)) 
    <lots of other stuff...> 
    (alter users assoc-in [id :ts] (Instant/now))))) 
+0

這實際上是ref的一個非常好的參數,而不是原子。我發現這個答案有助於解釋差異。 https://stackoverflow.com/a/9136699/457586 – DynamiteReed

相關問題