在Clojure中,我可以通过将step
参数调整为partition
来获取集合的重叠分区:
(partition 3 1 (range 20))
;; ((0 1 2) (1 2 3) (2 3 4) (3 4 5) ...)
core.async确实有分区功能,但由于它不接受步骤参数,我无法获得重叠分区:
(let [c (chan)]
(go (doseq [n (range 20)]
(>! c n)))
(go-loop [p (async/partition 3 c)]
(when-let [v (<! p)]
(prn v)
(recur p))))
;;[0 1 2]
;;[3 4 5]
;;[6 7 8]
我意识到这可能意味着能够不止一次从频道中读取相同的值。我也知道我可以创建自己的函数,从我想要的频道中读取尽可能多的值并构建我自己的分区。
但是我想知道是否有任何方法可以通过core.async提供的核心API实现这一目标。
PS。 sliding-buffer
没有做到这一点,因为我无法立刻窥视整个缓冲区。
答案 0 :(得分:4)
&#34;能够多次从频道中读取相同的值&#34;
违反core.async的原则。
每次从频道中读取值时,您都会从频道中取出此值
因此,关于通道行为的好处是,它保证每个值只读一次,如果没有值则不读取(阻塞/停放线程),如果通道关闭则不保留nil。
然后,开始解决问题的下一个问题应该是:为什么(在core.async上)至少有3个不同的函数可以在通道上输入/输出值。 因此,将通信通道视为集合点,在读者和作者可用之前,存在(core.async)3种不同的应用程序/线程行为:
>!! <!!
正在运行的线程将被阻塞,直到读者和作者都可用。>! <!
go块将创建一个伪线程,该线程将被停放,直到读取器和写入器都可用。此行为不会阻止正在运行的线程。take! put!
您只能按写入和读取顺序保证答案 1 :(得分:2)
这样做的一种方法是创建一个从通道读取,缓冲值并放入新通道的函数。我不确定这是多么惯用。
例如,只要从输入通道读取了所需的put!
项,每次输出后跳过n
项,下面的函数就会step
向量进入输出通道。
(defn stepped-partition [in n step]
(let [out (chan)]
(go-loop [buffer []]
(when-let [v (<! in)]
(let [new-buffer (conj buffer v)]
(if (= (count new-buffer) n)
(do
(put! out new-buffer)
(recur (subvec new-buffer step)))
(recur new-buffer)))))
out))
(def original (chan))
(def partitioned (stepped-partition a 3 2))
(go-loop []
(when-let [v (<! partitioned)]
(println v)
(recur)))
(async/onto-chan original [1 2 3 4 5 6 7 8 9])
;=> [1 2 3]
;=> [3 4 5]
;=> [5 6 7]
;=> [7 8 9]