60GB以上のテキストファイルを処理しています。これらのファイルは、可変長のヘッダーセクションとデータセクションに分かれています。 Clojure - メモリ不足の膨大なファイルを処理する
process-header
プロセスつのヘッダ行の文字列process-data
プロセス一つのデータ線列からヘッダ行を区別する
head?
述語:私は3つの機能を有していますメモリ内のデータベース
別のSOスレッドからファイルの読み取り方法を進めました。怠惰な一連の行。 1つの関数でいくつかの行を処理し、関数を1回切り替えて、次の関数で処理を続けるという考えがありました。
(defn lazy-file
[file-name]
(letfn [(helper [rdr]
(lazy-seq
(if-let [line (.readLine rdr)]
(cons line (helper rdr))
(do (.close rdr) nil))))]
(try
(helper (clojure.java.io/reader file-name))
(catch Exception e
(println "Exception while trying to open file" file-name)))))
が、私はそれが動作しますが、それはいくつかの理由ではなく、非効率的だ
(let [lfile (lazy-file "my-file.txt")]
(doseq [line lfile :while head?]
(process-header line))
(doseq [line (drop-while head? lfile)]
(process-data line)))
ようなもので、それを使用します。私は、データに到達するまで、単にprocess-head
を呼び出す代わりに
- と
process-data
を続行すると、ヘッダー行をフィルタ処理して処理した後、ファイル全体の解析を再開し、すべてのヘッダー行を処理してデータを処理する必要があります。これは、lazy-file
が意図したものとまったく反対です。 - メモリ消費量を見れば、プログラムはメモリにファイルを保持するのに必要な量のRAMを使用するように構築されています。
私のデータベースを使用すると効率的で慣用的な方法はありますか?
head?
述部の値に応じてヘッダーとデータを処理するには、マルチメソッドを使用することが考えられますが、これは特に重要なスピードに影響すると考えられます。常に真実に当てはまる。私はそれをまだベンチマーキングしなかった。
line-seqを構築してiterate
と解析する方が良いでしょうか?これはまだ私に使用する必要があります:whileと:drop-while、私は思います。
私の研究では、NIOファイルアクセスを使用することが数回言及されています。これはメモリ使用量を改善するはずです。私はそれを卒法で慣用的な方法で使用する方法をまだ見つけられませんでした。
多分私はまだ一般的なアイデアの悪い把握を持っている、どのようにファイルを処理する必要がありますか?
いつものように、どんな助けやアイデア、ツイートへのポインタも大歓迎です。
感謝。昨日私はベンチマークを行うためにいくつかのテストケースを書いた。それはそのことが判明しました ** A)**それは多くのメモリを消費する読み込み自体ではなく、データベース(btw、私のメモリ消費クレームは、コンパイルされたアプリケーションを実行することから来ているようです) ** B)*驚くべきことに、マルチメソッドとループ再帰のアプローチでは、約150%が必要になるでしょう。ファイルを2回開き、/ drop-whileの間に使用するのに必要な時間。 – waechtertroll
ファイルを読んでいる間にあなたのやり方が気に入っています。次の行がデータ行(イテレータースタイル)であるかどうかヘッダーパーサーチェックを行い、そうであれば、データパーサーからトランポリンを離れて試してみてください。各行のIf-elseは本当に遅いですが、ファイルは数百のヘッダー行と数億のデータ行に明確に定義されており、頭の読み取りには0.5秒もかかりません。私はまだ、トランポリンとイテレータをどのように組み合わせるかわからない... – waechtertroll