我遇到一个问题,我在一个非常大的搜索空间中搜索具有某些属性的数字(可能是无限的,但是对于整个空间而言绝对太大而无法适应内存)。所以我想要一个懒惰的序列,我过滤。我天真的方法是使用列表推导(for
)进行整个搜索,但这会在单个线程中执行搜索。有一些非常简单的方法来修剪搜索空间,搜索的某些部分也是计算密集型的。
我稍微不那么天真的做法是将简单的修剪放在for
表达式中,并使search
函数完成更难的工作。然后:(filter search (for [..... :when (prune)]))
。 reducers库中有filter
函数,但是that won't work on lazy seqs。由于内存限制,我无法从懒惰的seq转换。
那么,并行过滤延迟序列的好方法是什么?我最后的天真方法就像将序列粘在原子中一样:
(defn accessor-gen [lazys]
(let [s (atom [nil lazys])]
(fn []
(first (swap! s (fn [[_ s]] [(first s) (rest s)]))))))
然后我可以使用这个函数来搜索空间的六个左右的线程池。
问题:我有一种不安的感觉,我正在努力做到这一点。另外,我关注对原子的争论。是否有更直接的方法来并行使用延迟序列?最后,我的整个方法是否存在根本缺陷?有没有更好的方法,也许是一个不需要懒惰序列的方法?
答案 0 :(得分:1)
我要尝试的第一件事是过滤一个pmapped seq:
(defn search [i]
(println (Thread/currentThread) i)
(when (zero? (rem i 10))
i))
(take 10 (filter identity (pmap search (range))))
过滤将在单个线程中进行,但搜索将并行计算。
如果您实际想要并行执行的操作是过滤,则需要对lazy seq进行分区并将结果连接起来:
(defn search [numbers]
(doall (filter (fn [i] (zero? (rem i 10))) numbers)))
(take 10 (apply concat (pmap search (partition-all 1000 (range)))))