请在2024 Clojure 状态调查中分享您的看法!

欢迎!请参阅关于页面以了解更多关于它是如何工作的信息。

0
序列
编辑

我预计下面的操作将在所有可用的CPU(在这种情况下是12个)上并行化,但它在只有一个上运行。我犯了什么错误?

(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需要可折叠序列才能并行运行。

图片无法显示
具体来说,你需要实现 CollFold 的东西。出厂时,向量和一些其他类型(范围、迭代、哈希表)实现了它,但默认回退是使用串行 reduce。因此,简单的想法是使用向量,稍微复杂一些的是定义自己的可折叠性或实现 CollFold(使用 reducer 接口或 reify)。
0
图片无法显示

这是一个很好的问题!对这类数据的有效操作非常重要。

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

这篇 gist 展示了我们如何简化操作 csv 数据的一些方法,并将其与您所做的数据集/数据类型感知并行化版本(无怪乎快得多)的朴素解决方案进行了比较。

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

希望这能帮到您,并展示了一种处理此类问题的不同方法。

PS. 从您的问题中学习了关于 fnil 的知识,真不错!

图片无法显示
感谢您的有用回答。创建数据集似乎花去了大部分时间(约 82 秒,从 1 亿行),而处理本身非常快 - 1 亿行在约 10 秒内完成。
图片无法显示
编辑
当然,您非常受欢迎。是的,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 的内存,所以我能够修改代码来写入 100M 行 csv 和 nippy 数据集。磁盘上的 csv 大约是 ~658MB,nippy 大约是 ~537MB。csv 数据集加载需要 ~47 秒,而 nippy 数据集加载需要 ~2.8 秒。(
...