kiyoka.2012_04_01 RSSPLAIN

Related pages: !kiyoka.blog.list kiyoka.2012_04_07 !kiyoka.blog.2012_04
55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555544455555555555
5

[Ruby][Nendo] Ruby 2.0(開発版)に入ったEnumerable::Lazyを試してみた

5

ゆくゆくは Ruby 2.0に入るようだ。

5

今回、Ruby 2.0の開発版を実際に動かしてみた。

5
 Ruby 2.0 Enumerable::Lazy EXT
5

3389965080_eaa5bc957c_m (うちの猫がLazyな時の写真)

5

 

5

Lazyが無いとどうなるか

5

 

5

次の例ように、ファイルから行単位で処理するようなRubyプログラムがあるとする。

5

bashで書くならば、 "grep ruby test.txt | head -5" のような処理。

5

 

5
  File.open( 'test.txt' ) do |f|
5
    arr = f.map(&:chomp).grep(/ruby/).take( 5 )
5
    arr.each{ |x| puts x }
5
  end
5

 

5

一般的に、読みやすいコードを心掛けると上のように全行をメモリに読み込んで処理するように書くだろう。

5

mapとかeachを使ってメソッドチェーンを多用すれば簡潔に書けるからだ。

5

 

5

ただ、メソッドチェーンの度に新しいArrayが確保されるため、test.txtが大きいとメモリを大量に消費する。

5

Lazy(遅延評価)はこれを綺麗に解決してくれる。

5

 

5

 

5

Ruby 2.0をインストールする方法

5

 

5

Ruby 2.0をビルドしたいなら、githubからcloneするのが簡単だ。

5

masterブランチがRuby 2.0の開発版になっているようだ。

5
git clone https://github.com/ruby/ruby.git
5
Cloning into ruby...
5
remote: Counting objects: 222847, done.        
5
remote: Compressing objects: 100% (44673/44673), done.        
5
Receiving objects:  92% (206057/222847), 64.40 MiB | 317 KiB/s   pwd
5
remote: Total 222847 (delta 177021), reused 220708 (delta 176422)        
5
Receiving objects: 100% (222847/222847), 76.22 MiB | 310 KiB/s, done.
5
Resolving deltas: 100% (177021/177021), done.
5

 

5
~/work/github $ cd ruby/
5
~/work/github/ruby $ ls Makefile*
5
Makefile.in
5

 

5
~/work/github/ruby $ autoconf
5
~/work/github/ruby $ bash ./configure
5
checking build system type... x86_64-unknown-linux-gnu
5
checking host system type... x86_64-unknown-linux-gnu
5
   .
5
   .
5
.ext/include/x86_64-linux/ruby/config.h updated
5
verconf.h updated
5
ruby library version = 2.0.0
5
configure: creating ./config.status
5
config.status: creating Makefile
5
config.status: creating ruby-2.0.pc
5

 

5
~/work/github/ruby $ make dist
5
ruby ./tool/make-snapshot tmp 
5
Exporting trunk@35198
5
Exported revision 35198.
5
take a breath, and go ahead
5
creating configure... done
5
creating prerequisites...
5
   .
5
   .
5
prerequisites done
5
creating bzip tarball... /home/kiyoka/work/github/ruby/tmp/ruby-2.0.0-r35198.tar.bz2 done
5
creating gzip tarball... /home/kiyoka/work/github/ruby/tmp/ruby-2.0.0-r35198.tar.gz done
5
creating zip archive... /home/kiyoka/work/github/ruby/tmp/ruby-2.0.0-r35198.zip failed
5
* /home/kiyoka/work/github/ruby/tmp/ruby-2.0.0-r35198.tar.bz2
5
  SIZE:   9913268 bytes
5
  MD5:    943937f8635458fedfc271f97e6133c9
5
  SHA256: ed5850f393db8ec39568fcd9446566ebcdabe4584c0f8c7a827e21e0bd0a9e3a
5
5
* /home/kiyoka/work/github/ruby/tmp/ruby-2.0.0-r35198.tar.gz
5
  SIZE:   12561052 bytes
5
  MD5:    60bb6bdf08dcdbf424cd757b517ded75
5
  SHA256: 898aa4e3222d5585621112dd8c277d3e565a130540f2ea8a5bd4b0d70c7ad334
5
~/work/github/ruby $ 
5

 

5

できた tmp/*.tar.gz をオフィシャルリリースされた ruby-1.9.3-p125 の tar.gz と同様にビルド、インストールできる。

5

※ ちなみに、私は stowというツールでいろんなRuby環境をスイッチできるようにしている。

5

 

5

Lazyの効果

5

実際に大きなサイズのtest.txtを用意して試してみた。

5
$ du -sh test.txt 
5
198M    test.txt
5

 

5

Lazyなし

5
$ ruby ./lazy_sample.rb 
5
[without Lazy]
5
bioruby
5
eruby
5
fxruby
5
hruby
5
hruby's
5
=> VmPeak:       1282188 kB  (1252.1MB)
5

 

5

Lazyあり

5
$ ruby ./lazy_sample.rb lazy
5
[with    Lazy]
5
bioruby
5
eruby
5
fxruby
5
hruby
5
hruby's
5
=> VmPeak:         26280 kB    (25.6MB)
5

 

4

プロセスがどこまでも肥大したか(ピーク)を調べると、lazyを使ったバージョンは25.6MByteしかメモリを消費しないことがわかった。

4

".lazy." の6文字を追加しただけでこれだけの効果がある。素晴らしい。

4

 

5

実験したソースコード

5
 lazy_sample.rb
5
 sample for Enumerable::Lazy of Ruby 2.0 — GistEXT
5

 

5

感想

5

Rubyに遅延評価が入るとは思ってなかったのでこれは嬉しい。

5

私が作っているLisp処理系のNendoはRubyとのインテグレーション済みなので、Nendoのmapやfor-eachにEnumerable::Lazy型を渡せば同様にLazyに処理できるはず。(今度実験してみよう)

5

実は、普段Nendoで500MByteクラスのテキストファイルを処理することがよくある。その度に、メモリ消費量を削減するためにfor-eachで1行づつ処理するループをコーディングしていた。

5

もうその必要が無くなるだろう。Ruby 2.0が正式リリースされるのが本当に楽しみになったぞ、これは。

5

 

5

...comment disabled...