kiyoka.2012_08_11 RSSPLAIN

Related pages: !kiyoka.blog.list kiyoka.2012_08_12 !kiyoka.blog.2012_08
352555555555555555555555555555555455555455555455555555545455
3

[Nendo][Lisp] Kyoto.Lisp Hackathon でやったことのまとめ

5

Kyoto.lisp Hackathon #1EXT に参加してきた。

2
 logo120x80
5

KyotoでLisperが10人以上集ったのだけど、他の大きなイベントとぶつかっていたわりにはよく集ったのかも。

5

 

5

私は、前からやってみようと考えていたRuby 2.0(Trunk)のlazyをNendoで簡単に使えるようにする拡張にトライした。

5

 

5

解決したいこと

5

大きなテキストファイルを処理する際、メモリを節約するために逐次処理を意識した汚いコーディングに書き直すことがある。

5

これをなんとか、手続き型スタイルに書き直さずに関数型スタイルのまま、内部ではメモリ効率の良い処理をしてくれないか。

5

そんな都合の良い方法が見つかったのでトライしてみた。

5

遅延評価されたEmumerableを使えば思ったような効果が期待できると考えた。

5

 

5

Hackathon後、家に帰ってからコードを整理していくつかの勘違いも正すことができたので、ここに実験結果を書いておく。

5

後日、大袈裟な解決方法だと気がついてボツにしたコードも掲載し解説する予定。

5

 

5

実験対象のプログラム

5

約100MByteのテキストファイルを読み込んで加工・出力する、いわゆるフィルタプログラムで実験した。

5

書き捨てプログラムでは一番よく出てくるパターンだ。

5

 

5

効果

5

既存の仕組みだと、全ての入力行をプロセスにいったん蓄積するので、プロセスのピークメモリが大きい。

5

 

5

eagar.nndが、(f.readlines)した一番メモリを使う例。

5

generator.nndが、(f.lines)でジェネレータスタイルで書いた例。

5

lazy.nndが、Ruby 2.0のlazyを使った例。1.9.3ではLazyの機能が無いので自動的にフォールバックして遅延評価なしで動いている。

5

 

5

lazy_for_nendo_exam_graph

5

 

5

 

5

コード解説

5

 

5

eager.nnd

4

example #1 eager filter — GistEXT

5

赤色の部分は入力ファイルの全ての行をメモリ中に保持する。

5

全ての行を "<" ">" で囲んだ中間データもメモリ中に保持するので、入力行の2倍のメモリを消費する。

5

eager.nnd

5

 

5

generator.nnd

4

example #2 filter with generator — GistEXT

5

青色の部分(入力ストリーム)をジェネレータにして、入力行を全て読み込まないようにする。

5

但し中間データは入力行数分のメモリを消費する。

5

generator.nnd

5

 

5

lazy.nnd

4

example #3 lazy filter — GistEXT

5

入力ストリームをlazy指定するとlazyが伝搬する。緑色の部分はlazyなvectorとなっている。

5

このプログラムでは、どんなに入力テキストデータが巨大になってもメモリは60MByte程度しか消費しない。

5

しかも、関数型プログラミングスタイル(高階関数のチェーンによる宣言的プログラミング)が維持できている。

5

lazy.nnd

5

 

5

今後の予定

5

実験がうまくいったので、lazy-vectorという関数はそのままリリースする予定。(Nendo 0.6.5)

5

ただし、srfi-1のtakeなどの多くの関数がlazy-vectorをサポートしないとNendoの処理系全体での旨味が出し切れないので順次対応していく。Nendo 0.6.6以降かな…

5

 

4

学び

5

やっぱりブログ記事で文章化しないと、成果はまとまらないことを実感した。

4

今後はHackathon中もブログ(またはDokyumentoj)を書きながら頭を整理して作業しようと思う。

5

 

5

...comment disabled...