mmapscanner
TRANSCRIPT
MmapScannerとみたまさひろ2011-07-18
自己紹介id:tmtms
@tmtms
日本MySQLユーザ会
長野ソフトウェア技術者グループ(NSEG)
重要「MySQL徹底入門第三版」近日発売
画像は第二版
Rubyたぶん13年くらい
バージョン 1.1 から
「Rubyをイヤイヤ使わされてる人」を作る仕事
SIerのRubyistの悲しき紋章
趣味誰も使わないライブラリを作る
自分でも使わない
MySQL/RubyMySQL C library wrapper
割と使われてる
オワコン
Ruby/MySQLpure Ruby
あまり使われてない
名前が悪い
OptConfigOptionParser みたいなもの
設定ファイルから読む
自動補完する/しない
--help に出すかどうか
複数指定した時のふるまい最後を採用/配列で全部/エラー
LightCsvCSVパーサー
「うわっRubyのCSV遅すぎ」
ついカッとなって作った
速度
ken_all.csv(123000行, 12MB)
速度
ken_all.csv(123000行, 12MB)
LightCsv103行 (コメント/空行除く)
CSV のパースをするだけなのに
CSVパース物理行単位で処理できない
ほげ,"改行を\r\n含むカラム",ふが
固定サイズで読むと CR と LF がわかれたり
全部読んじゃえメモリ食う
mmap(2)ファイルをメモリにマッピング
read通常は open して少しずつ read
mmapファイル全体(または一部)をメモリにマップ
mmap速い
メモリを食わない
大きなファイルで有用
Rubyからは使いにくいメモリを直接さわれない
Stringとして扱う時はコピーが必要
MmapScannerRuby の拡張ライブラリ
StringScanner の mmap 版
mmap 領域を正規表現で走査
取り出したものも MmapScanner
MmapScanner部分的に取り出しても同じメモリを共有
使い方
f = File.open("filename")m = MmapScanner.new(f)word = m.scan(/[a-z0-9_]+/i)word # => MmapScannerword.to_s # => String
CSVパーサー
require 'mmapscanner'class MmapCSV include Enumerable def initialize(filename) File.open(filename) do |f| @ms = MmapScanner.new(f) end end def each rec = [] until @ms.eos? if @ms.skip(/\"((?:\"\"|[^\"])*)\"(,|\r\n|\n|\z)/n) rec.push @ms.matched_str(1).gsub(/\"\"/,'"') elsif @ms.skip(/([^,\"\r\n]*)(,|\r\n|\n|\z)/n) rec.push @ms.matched_str(1) else raise "invalid format: #{@ms.rest.slice(0,20).to_s}" end unless @ms.matched_str(2) == ',' yield rec rec.clear end end endend
速度
ken_all.csv(123000行, 12MB)
課題1.9 only
ASCII-8BIT only
明に munmap できない
FAQどうせ拡張ライブラリ作るんだったらCSVパーサーをCで書けば良かったんじゃね?
目的と手段の正しい理解目的: RubyでCSVパーサーを書く
手段: 拡張ライブラリ
以上