Clojure 写入文件映射与 doseq

jim*_*myc 5 time clojure map output

我需要根据 Clojure 集合的元素将一些内容写入文件,我可以这样做——但我遇到了一些让我感到困惑的事情。可能是因为我不完全理解时间宏,但是当我执行以下操作时:

=> (def nums (take 100000 (repeatedly #(str (rand-int 1000) " "))))
   (defn out1 [nums] (doseq [n nums] (spit "blah1.txt" n :append true)))
   (defn out2 [nums] (map #(spit "blah2.txt" % :append true) nums))
#'test.core/nums
#'test.core/out1
#'test.core/out2
=> (time (out1 nums))
"Elapsed time: 19133.247 msecs"
nil
=> (time (out2 nums))
"Elapsed time: 0.209 msecs"
(nil nil nil nil ... )
Run Code Online (Sandbox Code Playgroud)

使用 map (out2) 的实现运行速度明显更快。但是,当我转到文件夹并查看文件时,它会在给出 Elapsed time 后继续进行写入,并且 (nil ...) 输出会等到写入完成后才能显示。这让我相信他们实际上都在花费相同的时间。

那么,在这种情况下使用 doseq 和 map 有什么区别呢?哪种方式总体上会更好?谢谢

Art*_*ldt 3

doseq 是热切的(而不是懒惰的),并且当你调用它时就会完成所有的工作。 map 是惰性的,并立即返回一个惰性序列,表示读取结果时将发生的工作。

因此,当 repl 打印地图的结果(所有 nils)而不是您正在计时的部分时,地图正在执行工作。要解决此问题,请调用doalldorun围绕调用map.

(time (doall (out2 nums)))
Run Code Online (Sandbox Code Playgroud)

更重要的错误是,您不打印结果(或以其他方式使用它),那么内容根本不会写入文件。一般来说,对于纯粹的副作用操作doseq可能是更好的选择。