我有一个lazy-seq,每个项目需要一些时间来计算:
(defn gen-lazy-seq [size]
(for [i (range size)]
(do
(Thread/sleep 1000)
(rand-int 10))))
是否可以逐步评估此序列并打印结果。当我尝试使用for
或doseq
clojure处理它时,总是会在打印任何内容之前实现整个lazy-seq:
(doseq [item (gen-lazy-seq 10)]
(println item))
(for [item (gen-lazy-seq 10)]
(println item))
在打印任何内容之前,两个表达式都会等待10秒钟。我已经看过doall和dorun作为解决方案,但是它们要求lazy-seq生成函数包含println。我想分别定义一个lazy-seq生成函数和lazy-seq打印函数,并使它们逐项协同工作。
尝试这样做的动机: 我有消息通过网络进入,我想在收到所有消息之前开始处理它们。同时,在lazy-seq中保存与查询相对应的所有消息会很好。
编辑1:
JohnJ的回答显示了如何创建一个将逐步评估的lazy-seq。我想知道如何逐步评估任何lazy-seq。
我很困惑,因为如上所述在gen-lazy-seq上运行(chunked-seq? (gen-lazy-seq 10))
或者在JohnJ的答案中定义的都返回false。那么问题不在于一个人创建一个分块序列而另一个不会。
在this回答中,显示了一个函数seq1,它将一个chunked lazy-seq变成一个非chunked的seq1。尝试该功能仍然会产生延迟输出的相同问题。我认为延迟可能与repl中的某种缓冲有关,所以我也尝试打印seq中每个项目实现的时间:
(defn seq1 [s]
(lazy-seq
(when-let [[x] (seq s)]
(cons x (seq1 (rest s))))))
(let [start-time (java.lang.System/currentTimeMillis)]
(doseq [item (seq1 (gen-lazy-seq 10))]
(let [elapsed-time (- (java.lang.System/currentTimeMillis) start-time)]
(println "time: " elapsed-time "item: " item))))
; output:
time: 10002 item: 1
time: 10002 item: 8
time: 10003 item: 9
time: 10003 item: 1
time: 10003 item: 7
time: 10003 item: 2
time: 10004 item: 0
time: 10004 item: 3
time: 10004 item: 5
time: 10004 item: 0
对JohnJ的gen-lazy-seq版本做同样的事情按预期工作
; output:
time: 1002 item: 4
time: 2002 item: 1
time: 3002 item: 6
time: 4002 item: 8
time: 5002 item: 8
time: 6002 item: 4
time: 7002 item: 5
time: 8002 item: 6
time: 9003 item: 1
time: 10003 item: 4
编辑2:
不仅生成的序列有这个问题。无论seq1包装如何,都无法逐步处理使用map生成的序列:
(defn gen-lazy-seq [size]
(map (fn [_]
(Thread/sleep 1000)
(rand-int 10))
(range 0 size)))
但是这个序列也是用地图创建的:
(defn gen-lazy-seq [size]
(map (fn [_]
(Thread/sleep 1000)
(rand-int 10))
(repeat size :ignored)))
答案 0 :(得分:4)
Clojure的懒惰序列经常被分块。如果你使用大size
s(在这种情况下减少线程休眠时间将有所帮助),你可以在你的例子中看到工作中的分块。另请参阅these related SO posts。
虽然for
似乎已被分块,但以下内容并未按预期运行:
(defn gen-lazy-seq [size]
(take size (repeatedly #(do (Thread/sleep 1000)
(rand-int 10)))))
(doseq [item (gen-lazy-seq 10)]
(println item))
“我有消息通过网络进入,我想在收到所有消息之前开始处理它们。”如果你懒得处理它们,实际上应该是这种情况。