并行过滤延迟序列

时间:2014-10-12 20:32:19

标签: multithreading concurrency clojure lazy-sequences

我遇到一个问题,我在一个非常大的搜索空间中搜索具有某些属性的数字(可能是无限的,但是对于整个空间而言绝对太大而无法适应内存)。所以我想要一个懒惰的序列,我过滤。我天真的方法是使用列表推导(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)]))))))

然后我可以使用这个函数来搜索空间的六个左右的线程池。

问题:我有一种不安的感觉,我正在努力做到这一点。另外,我关注对原子的争论。是否有更直接的方法来并行使用延迟序列?最后,我的整个方法是否存在根本缺陷?有没有更好的方法,也许是一个不需要懒惰序列的方法?

1 个答案:

答案 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)))))