2017-06-12 64 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

相关问题