在尝试复制一些websockets示例时,我遇到了一些我不理解的行为,似乎无法找到文档.简化,这是我在lein中运行的一个例子,它应该每秒为共享映射中的每个元素运行一次函数:
(def clients (atom {"a" "b" "c" "d" }))
(def ticker-agent (agent nil))
(defn execute [a]
(println "execute")
(let [ keys (keys @clients) ]
(println "keys= " keys )
(doseq [ x keys ] (println x)))
;(map (fn [k] (println k)) keys)) ;; replace doseq with this?
(Thread/sleep 1000)
(send *agent* execute))
(defn -main [& args]
(send ticker-agent execute)
)
Run Code Online (Sandbox Code Playgroud)
如果我用地图运行这个我得到
execute
keys= (a c)
execute
keys= (a c)
...
Run Code Online (Sandbox Code Playgroud)
第一个令人困惑的问题:我理解我可能会错误地使用地图,因为没有返回值,但这是否意味着内部println被优化了?特别是如果我在repl中运行它:
(map #(println %) '(1 2 3))
Run Code Online (Sandbox Code Playgroud)
它工作正常吗?
第二个问题 - 如果我使用doseq而不是map来运行它,我可以遇到执行代理停止的条件(我会在这里添加,但是很难隔离/重新创建).显然,我可能会遗漏一些可能与锁定地图键集有关的东西?我甚至能够将共享地图移出原子.我在clojure地图上是否有默认的同步化?
map很懒.这意味着它不会计算任何结果,直到从它重新运行的数据结构中访问结果.这意味着如果不使用它的结果,它将不会运行任何东西.
当您map从repl 使用时,repl的print阶段访问数据,这会导致映射函数中的任何副作用被调用.在函数内部,如果不调查返回值,则不会发生映射函数中的任何副作用.
您可以使用doall强制完整评估延迟序列.dorun如果您不需要结果值但想要确保调用所有副作用,则可以使用.你也可以使用mapv哪个不是懒惰的(因为向量从不是懒惰的),并且为你提供了一个关联数据结构,这通常很有用(更好的随机访问性能,优化了附加而不是预先添加).
编辑:关于你的问题的第二部分(从评论中移动这里).
不,没有任何关于doseq这会挂起您的执行,尝试检查代理的代理错误状态以查看是否存在异常,因为代理停止执行并在默认情况下停止接受新任务(如果它们遇到错误情况).您还可以使用set-error-model和set-error-handler!自定义代理的错误处理行为.