请在2024年Clojure状态调查!分享您的想法。

欢迎!请参阅关于页面,了解有关该工作方式的更多信息。

0
序列
编辑

我原本预计以下操作将并行化所有可用的CPU(本例中为12个),但它只在一个CPU上运行。我做了什么错事?

(ns csv2summap.core
  (:require [clojure.data.csv :as csv]
            [clojure.java.io :as io]
            [clojure.core.reducers :as r])))

(with-open [writer (io/writer "numbers.csv")]
  (csv/write-csv
   writer
   (take 10000000
         (repeatedly #(vector (char (+ 65 (rand-int 26))) (rand-int 1000))))))

(defn sum-vals
([] {})
([m [k v]]
 (update m k (fnil + 0) (Integer/parseInt v))))

(defn merge-sums
([] {})
([& m] (apply merge-with + m)))

(time
(with-open [reader (io/reader "numbers.csv")]
  (doall
   (r/fold
    (/ 10000000 12)
    merge-sums
    sum-vals
    (csv/read-csv reader)))))
(def n-cpu (.availableProcessors (Runtime/getRuntime)))
=>12
(ns csv2summap.core
  (:require [clojure.data.csv :as csv]
            [clojure.java.io :as io]
            [clojure.core.reducers :as r])))

-

(defproject csv2summap "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [[org.clojure/clojure "1.10.1"]
                 [org.clojure/data.csv "1.0.0"]]
  :repl-options {:init-ns csv2summap.core})

2 答案

+1

选中
 
最佳答案

感谢Clojurians聊天室的Sean Corfield和Adrian Smith,我现在明白,r/fold需要可折叠序列才能并行运行。

具体来说,你需要实现CollFold。 默认情况下,向量和一些其他类型(范围、迭代、哈希表)实现了它,但默认回退是使用序列求和。 因此,简单的方法是使用向量,略微复杂的方法是定义自己的可折叠性或实现CollFold(使用reducer API或reify)。
0

这是一个很好的问题!在高效操作这类数据方面非常关键。

为此,我们开发了一些相关库。

以下代码片段展示了我们如何简化处理CSV数据的操作,并比较了您所执行的对数据集/数据类型感知的并行化版本(毫不意外,这要快得多)的原始解决方案与累加/合并。

https://gist.github.com/harold/7335b78606f8e962f2b385f1ed79d15c

希望这有助于理解,并展示了处理这类问题的一种不同的方法。

PS. 从你的问题中我了解到了 fnil,真是太棒了!

感谢您丰富的答案。创建数据集似乎花费了大部分时间(约为82秒从1亿行),而处理本身非常快,约10秒处理1亿行。
by
编辑 by
当然,欢迎你。是的,100M真的很多行!解析200M数字肯定会花一些时间。你的问题关于并行合并/求和,所以我的代码将这部分工作分离出来。如果你想优化数据集的保存和加载,通常使用`nippy`比CSV要快得多。请查看`tech.io/put-nippy!`和`tech.io/get-nippy`。
by
感谢。尝试使用(ds/write-csv! (ds/->dataset source-data) 或 (io/put-nippy! "./data.nippy" (ds/->dataset source-data))在我的机器上使堆栈溢出。我用原来的代码生成了csv(并手动添加了标题)。
by
明白了。这很有道理,也是`clojure.data.csv`流式处理能力的酷例子。这台机器有32GB的RAM,所以我能够修改代码写出100M行csv和nippy数据集。在磁盘上的csv约为658MB,而nippy约为537MB。csv数据集加载大约需要47秒,而nippy数据集加载大约需要2.8秒。
...