当您使用它时,此来源会自然阻塞,因此您不必做任何非常花哨的事情。只需(mapcat deref):
(doseq [x (take 16 (mapcat deref (-source- )))]
(println {:value x :time (System/currentTimeMillis)}))
{:value 1, :time 1597725323091}
{:value 2, :time 1597725323092}
{:value 1, :time 1597725323092}
{:value 2, :time 1597725323093}
{:value 1, :time 1597725323093}
{:value 2, :time 1597725323093}
{:value 1, :time 1597725323194}
{:value 2, :time 1597725323195}
{:value 1, :time 1597725323299}
{:value 2, :time 1597725323300}
{:value 1, :time 1597725323406}
{:value 2, :time 1597725323406}
{:value 1, :time 1597725323510}
{:value 2, :time 1597725323511}
请注意前几件物品是如何同时出现的,然后每对物品都按您预期的时间交错排列?这是由于众所周知的(?)事实,出于性能原因,apply(以及因此使用apply concat 实现的mapcat)比必要的更急切。如果即使在前几项上获得正确的延迟对您很重要,您可以简单地实现自己的 apply concat 版本,它不会针对短输入列表进行优化。
(defn ingest [xs]
(when-let [coll (seq (map (comp seq deref) xs))]
((fn step [curr remaining]
(lazy-seq
(cond curr (cons (first curr) (step (next curr) remaining))
remaining (step (first remaining) (next remaining)))))
(first coll) (next coll))))
A. cmets 中的 Webb 提出了一个等效但更简单的实现:
(defn ingest [coll]
(for [batch coll,
item @batch]
item))