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 Slack通道的Sean Corfield和Adrian Smith,我现在明白r/fold需要在可折叠序列上运行才能并行化。

by
具体来说,你需要一些实现了 CollFold 的东西。直接使用时,向量和一些其他类型(例如,范围、迭代、哈希表)实现了它,但默认的回退是使用串行归约。因此,简单的思路是使用向量,稍微复杂一点是定义自己的可折叠类型或实现 CollFold(使用归约器 API 或 reify)。
0
by

这是一个非常好的问题!高效地操作此类数据是非常重要的。

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

这个示例展示了我们如何简化处理 csv 数据的一些方法,并将其与你在数据集/数据类型感知的并行版本中进行的求和/合并的原始解决方案进行了比较(这个并行版本明显快得多)。

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

希望这有助于您,并展示了解决这个问题的一个不同方法。

PS。从您的提问中学习了有关 fnil 的内容,真的很有趣!

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