Concurrency Clojure-映射和还原之间的差异//将一个转换为另一个

Concurrency Clojure-映射和还原之间的差异//将一个转换为另一个,concurrency,clojure,Concurrency,Clojure,我正在尝试将并发应用于我的程序,我想使用pmap,但我不确定如何将其应用到我当前的代码中。该功能对于单核来说是正确的,但理想情况下,我希望以某种方式用pmap替换reduce,并实现相同的结果。首先,您试图构建的功能称为频率: 事实上,它是单线程的。所以让我们试着让它平行 使用reduce的最初方法是正确的方向,尽管它也不是并行的,但可以使用它来使用clojure的标准库并发功能,即 首先,让我们稍微重写一下reducer函数,做同样的事情,但以更惯用的方式,它是可选的,但有利于可读性: 关联%

我正在尝试将并发应用于我的程序,我想使用pmap,但我不确定如何将其应用到我当前的代码中。该功能对于单核来说是正确的,但理想情况下,我希望以某种方式用pmap替换reduce,并实现相同的结果。

首先,您试图构建的功能称为频率:

事实上,它是单线程的。所以让我们试着让它平行

使用reduce的最初方法是正确的方向,尽管它也不是并行的,但可以使用它来使用clojure的标准库并发功能,即

首先,让我们稍微重写一下reducer函数,做同样的事情,但以更惯用的方式,它是可选的,但有利于可读性:

关联%1%2 inc%1%2 0=>更新%1%2 fnil inc 0

然后,我们可以使用fold接近平行reduce:

其思想是,如果集合足够长,它会将集合按块分割,然后将块的结果与以下合并:

还要注意,集合应该是“可折叠的”。默认情况下,持久性向量和映射是可折叠的,re-seq result不是,所以您应该首先将其转换为vector:vec re-seq..x s,否则您将无法获得任何并行化,只能返回到普通的reduce

显然,您可以使用pmap来实现这一点,使用相同的策略:拆分->映射->合并:

user> (pfreq [1 2 1 3 1 4 1 5 2])
;;=> {1 4, 2 2, 3 1, 4 1, 5 1}

但这并不像还原器管道那样灵活和强大。

您可能希望在问题中包含Example.txt的内容。map将函数应用于某个序列的每个元素。另一方面,reduce应用一个reduce函数,在某个序列的所有或某些元素上获取init/previous结果和序列中的下一项。您可以通过reduce实现某种映射,但不能反过来实现。我认为对于你的问题,你应该看一眼fnil是可爱的。
user> (frequencies [1 2 1 3 1 4 4])
;;=> {1 3, 2 1, 3 1, 4 2}
(require '[clojure.core.reducers :as r])

(defn pfreq [data]
  (r/fold
   (partial merge-with +)
   (fn [acc k] (update acc k (fnil inc 0)))
   data))
user> (pfreq [1 2 1 3 1 4 1 5 2])
;;=> {1 4, 2 2, 3 1, 4 1, 5 1}
(defn pfreq2 [chunk-size data]
  (->> data
       (partition-all chunk-size)
       (pmap frequencies)
       (apply merge-with +)))