2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |
2010-12-07
READ系関数のEOF-ERROR-Pを活用できないか
Common Lisp | |
READ系関数のEOF-ERROR-PはデフォルトがTですが、普通使うときは、大抵NILにすることが多いと思います。
これのデフォルトがNILだったら、
(loop :for line := (read-line in nil) :while line :collect line)
ではなく、
(loop :for line := (read-line in) :while line :collect line)
のようにすっきり書けたりするのになと常々思っていますが、逆に、これを活用できないかということで、以前、積極的にEND-OF-FILEシグナルを拾いに行く試みをしたことがありました。
今日CLerのquekさんとの雑談の中で、もしかしたらループの中でEOFかどうかを比較するコストが低いかもしれず、結果として速いかもしれない、という話になり折角なので実験してみることにしました。
まずは、/usr/share/dict/wordsでの比較。98569行のファイルです。
;; EOFをつかまえる (dotimes (i 100) (with-open-file (in "/usr/share/dict/words") (atap 0 (handler-case (loop :for c := (read-char in) :do (incf it)) (end-of-file () nil))))) ;⇒ NIL ---------- Evaluation took: 7.640 seconds of real time 7.620000 seconds of total run time (7.580000 user, 0.040000 system) 99.74% CPU 18,289,984,221 processor cycles 1,200,560 bytes consed Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz ;; atap (atap 0 ...) ≡ (LET ((IT 0)) ... IT)
;; 通常 (dotimes (i 100) (with-open-file (in "/usr/share/dict/words") (loop :for c := (read-char in nil nil) :while c :count c))) ;⇒ NIL ---------- Evaluation took: 7.996 seconds of real time 7.990000 seconds of total run time (7.900000 user, 0.090000 system) 99.92% CPU 19,144,510,308 processor cycles 1,102,048 bytes consed Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz
何度か平均してみましたが、極わずかのほんのちょっとだけ速い気がします。
■
次に512MBのファイルの読み込みを試してみます
$ dd if=/dev/zero of=/tmp/test.img bs=1024 count=$((1024*512))
;; 通常 ループ内では、-1と比較 (with-open-file (in "/share/music/tmp/test.img" :element-type '(unsigned-byte 8)) (loop :for b := (read-byte in nil -1) :until (= -1 b) :count b)) ;⇒ 536870912 ---------- Evaluation took: 35.383 seconds of real time 34.980000 seconds of total run time (34.690000 user, 0.290000 system) 98.86% CPU 84,706,093,341 processor cycles 512,976 bytes consed Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz
;; EOFを掴まえる (with-open-file (in "/share/music/tmp/test.img" :element-type '(unsigned-byte 8)) (atap 0 (handler-case (loop :for c := (read-byte in) :do (incf it)) (end-of-file () nil)))) ;⇒ 536870912 ---------- Evaluation took: 34.367 seconds of real time 33.790000 seconds of total run time (33.520000 user, 0.270000 system) 98.32% CPU 82,272,802,536 processor cycles 506,608 bytes consed Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz
これもほんのちょっ〜とだけ速い気がします。
おまけだと、IGNORE-ERRORSで捕捉しても速いことは速いです。スタイル的に微妙ですが…。
(with-open-file (in "/share/music/tmp/test.img" :element-type '(unsigned-byte 8)) (ignore-errors (loop (read-byte in)))) ;⇒ NIL ---------- Evaluation took: 32.416 seconds of real time 32.330000 seconds of total run time (32.040000 user, 0.290000 system) 99.73% CPU 77,605,457,589 processor cycles 478,112 bytes consed Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz
■
結論としては、微妙〜に速い気がする程度という感じになりましたが、探してみれば良い使いどころがあったりすることに期待したいです。逆に使ったら絶対駄目なところがあるのかもしれませんが。
おまけ HANDLER-CASEでEND-OF-FILEを掴まえるスタイルの欠点
HANDLER-CASEでEND-OF-FILEを掴まえるスタイルの欠点ですが、必ずエラーで抜けるため、フォームの返り値が使えないという欠点があります。
周りを値を収集するフォームで囲ってやらないと使い勝手が悪くなりますが、ここで、SeriesのGATHERERを使うと綺麗に書けます。
(with-open-file (in "/etc/passwd") (gatherlet ((g collect)) (handler-case (loop (next-out g (read-line in))) (end-of-file () nil)) (result-of g))) ;; gatherer (with-open-file (in "/etc/passwd") (gathering ((g collect)) (handler-case (loop (next-out g (read-line in))) (end-of-file () nil))))
まあ、Seriesには、SCAN-FILEがありますが。
■
コメントを書く