我有一个函数,它会加载很多用户(需要一段时间)并将它们存储在原子中。我想知道将用户加载到let绑定中然后重置原子和直接在原子reset!函数中加载它们之间是否有任何区别?
(let [all-users (get-users)]
(reset! users all-users))
或者
(reset! users (get-users))
由于reset!
是一个函数,对(reset! users (get-users))
的调用将像Clojure中的任何其他函数调用一样:调用中的每个S表达式都将被评估,然后作为参数传递给该函数。这意味着(get-users)
的计算将首先发生,并将结果传递给reset!
。因此,这将与let
表单完全相同。
swap!
形成对比这些问题在swap!
中发挥作用。因为您向swap!
发送要在事务内调用的函数,所以您可以更好地控制长时间运行的作业是在事务内还是在事务外发生。例如,如果您有poll-users-updates
和update-users-from-poll
函数,您可以将对第一个函数的调用设置为在事务内或事务外发生:
; outside the transaction
(swap! users update-users-from-poll (poll-users-updates))
; inside the transaction
(swap! users (fn [users] (update-users-from-poll users (poll-users-updates))))
poll-users-updates
函数还需要操作 users
数据的当前状态(例如,查找最近更新的用户的时间戳,以便更有效地进行轮询),那么第二种方法可能更可取,因为它会确保在进行轮询时拥有最新的 users
值。使用reset!
时不会有任何差异。但是,当使用其他操作原子的函数时,要小心,因为产生值的函数可能会被调用多次。例如,在swap!
中就是这种情况。