大規模なシーケンスでloop/recurを使用すると、怠惰なシーケンスがOutOfMemoryErrorを引き起こす可能性があることを読んでいます。私はそれを処理するためにメモリから3MBのファイルをロードしようとしています。そして、これは私に起こっていると思います。しかし、それを修正するための慣用的な方法があるかどうかはわかりません。私はdoallを入れてみましたが、私のプログラムは終了していないようです。小さな入力は働く:Clojure OutOfMemoryError
小さな入力(ファイルの内容):AAABBBCCC 正しい出力:((65 65)(65 66)(66 66)(67 67)(67 67))
コード:
を(def file-path "/Users/me/Desktop/temp/bob.txt")
;(def file-path "/Users/me/Downloads/3MB_song.m4a")
(def group-by-twos
(fn [a-list]
(let [first-two (fn [a-list] (list (take 2 a-list)))
the-rest-after-two (fn [a-list] (rest (rest a-list)))
only-two-left? (fn [a-list] (if (= (count a-list) 2) true false))]
(loop [result '() rest-of-list a-list]
(if (nil? rest-of-list)
result
(if (only-two-left? rest-of-list)
(concat result (list rest-of-list))
(recur (concat result (first-two rest-of-list))
(the-rest-after-two rest-of-list))))))))
(def get-the-file
(fn [file-name-and-path]
(let [the-file-pointer
(new java.io.RandomAccessFile (new java.io.File file-name-and-path) "r")
intermediate-array (byte-array (.length the-file-pointer))] ;reserve space for final length
(.readFully the-file-pointer intermediate-array)
(group-by-twos (seq intermediate-array)))))
(get-the-file file-path)
私が上で述べたように、私がたくさんの場所で駄目にすると、それは終わっていないようです。これを大容量ファイル用に実行するにはどうしたらいいですか?何が必要なのかを行うことの認知的な負担を取り除く手段がありますか?いくつかのルール?
私は最終的にバイトではなく文字を読む必要があることに注意してください。あるいは、むしろ、私は最終的に各16ビットから符号付き数値を取得しようとしています。私はそれらのペアを取って、次のパスの間にマップで単一の数字に変えようとしていました。これを行うにはおそらくもっと良い方法があります... – MarkL4
関連性のある徹底的な議論があります:(http://programming-puzzler.blogspot.com/2009/01/laziness-in-clojure-traps-workarounds.html) – MarkL4
Clojureの豊富な組み込み関数とライブラリを使用して、コグニティブな負担を軽減する方法については、できるだけ独自のコードを書くようにしてください。 'group-by-twos'は本当に大きいですが、それほど効果はありません。また '(if(=(count a-list)2)true false)'は '(=(count a-list)2)'を冗長に表現する方法です。 –