100 万行のファイルを解析しようとしています。各行は、書籍に関する情報 (著者、内容など) を含む json 文字列です。を使用しようとするとプログラムが をスローするため、 iotaを使用してファイルをロードしています。また、チェシャを使用して文字列を解析しています。プログラムは単にファイルをロードし、すべての本のすべての単語を数えます。OutOfMemoryError
slurp
私の最初の試みpmap
には、重い作業が含まれていましたが、これは基本的にすべての CPU コアを利用することになると考えました。
(ns multicore-parsing.core
(:require [cheshire.core :as json]
[iota :as io]
[clojure.string :as string]
[clojure.core.reducers :as r]))
(defn words-pmap
[filename]
(letfn [(parse-with-keywords [str]
(json/parse-string str true))
(words [book]
(string/split (:contents book) #"\s+"))]
(->>
(io/vec filename)
(pmap parse-with-keywords)
(pmap words)
(r/reduce #(apply conj %1 %2) #{})
(count))))
すべてのコアを使用しているように見えますが、各コアがその容量の 50% 以上を使用することはめったにありません。私の推測では、pmap のバッチ サイズに関係しているため、いくつかのコメントがライブラリを参照しているという比較的古い質問clojure.core.reducers
に出くわしました。 .
を使用して関数を書き直すことにしましたreducers/map
:
(defn words-reducers
[filename]
(letfn [(parse-with-keywords [str]
(json/parse-string str true))
(words [book]
(string/split (:contents book) #"\s+"))]
(->>
(io/vec filename)
(r/map parse-with-keywords)
(r/map words)
(r/reduce #(apply conj %1 %2) #{})
(count))))
ただし、CPU の使用率は悪く、以前の実装と比較して完了するまでに時間がかかります。
multicore-parsing.core=> (time (words-pmap "./dummy_data.txt"))
"Elapsed time: 20899.088919 msecs"
546
multicore-parsing.core=> (time (words-reducers "./dummy_data.txt"))
"Elapsed time: 28790.976455 msecs"
546
私は何を間違っていますか?大きなファイルを解析するとき、mmap の読み込み + レデューサーは正しいアプローチですか?
編集:これは私が使用しているファイルです。
EDIT2:iota/seq
代わりに次のタイミングがありますiota/vec
:
multicore-parsing.core=> (time (words-reducers "./dummy_data.txt"))
"Elapsed time: 160981.224565 msecs"
546
multicore-parsing.core=> (time (words-pmap "./dummy_data.txt"))
"Elapsed time: 160296.482722 msecs"
546