Skip to content

IO_memo

akiray03 edited this page Mar 14, 2013 · 14 revisions

実装の方針

  • IOのバッファリング等を FILE* に任せる (iij/mrubyのIO実装)
  • バッファリングをCでスクラッチ実装する
  • バッファリング無しのIO(sysread,syswrite)をRubyメソッドで提供する。バッファリングはmrubyで実装する(かもしれない)

そもそも

  • mrubyの用途として、IOバッファリングってどんなものが求められてる?
  • IOの上に乗っかるSocketはバッファリング欲しがるかも
  • 小さなデバイスの場合には、そもそもFILE*使えないかもしれない
  • 大きなリソースがある場合には、バッファリング云々よりも、全部読んじゃう/行単位で読み進める、でも良いのか。

調べること / 決めたこと

  • fptr->f2 の使われ方 (後で泣かないように!)
    • pipeでread/writeが使えるときに、write用に利用している
    • select の writers
  • バッファリングはmrubyで実装する。IO.syswrite, sysread C言語で実装して提供する。
  • IO.new と IO.popen の挙動から確認していく
  • 書く側は、IO#write がバッファされるOutputのプリミティブなメソッド。
    • write buffer を用意するならば、IO#writeで考慮すれば良い
    • だけど、たぶん write buffer は要らない (?)
  • 読む側は、バッファされるプリミティブなメソッドが示されていない
    • IO#gets, IO#getc, IO#readlines, ... etc は、バッファリングしつつ IO#sysread を呼べばOK
    • IO#read も IO#sysread を呼べばOK
    • IO#read(size) は、 sizeに達するまで待つ
    • バッファリングしつつIO#sysreadを呼ぶ、ユーティリティメソッドを用意する。
      • IO#read(size) との違いは、 sizeが maxlength である点
      • (maxlengthに達していなくても、読めるだけ読んだら、ブロックせずに返す)

IO#_read(maxlength)

  • 指定されたmaxlengthを上限に、IO#sysreadを使ってデータを読み込む
    • IO#read(size) と違って、 size に達していなくても、読み込むデータが無くなれば、そこまでのデータを返す
  • EOFに達した時は EOFError を返す (IO#sysreadと同じ)
  • maxlengthは、バッファサイズ(BUF_SIZE)以下でなければならない (maxlength <= BUF_SIZE)

mode, flag もろもろ

  • IO.new で指定する mode

    • "r" や "w" など (String) ... (1)
    • File::Constants::RDONLY など (Integer) ... (2)
  • open(2) に渡す mode ... (3)

  • mrubyのIO実装で条件判定に用いる flag ... (4)

  • このうち、 (2) と (3) は同じ

  • 以下のように名前を付ける

    • modestr : "r" や "w" など
    • modenum : open(2)に渡すmode
    • flags : mrubyのIO実装で条件判定に用いるflag (FMODE_XXX として mruby/ext/io.h で定義)
to\from modestr modenum flags
modestr x x x
modenum x x o
flags o o x
  • 実装する変換関数
    • static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr)
    • static int mrb_io_modenum_to_flags(mrb_state *mrb, int modenum)
    • static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags)

Benchmark

t1 = Time.now
10000.times do
  fd = IO.sysopen("AUTHORS")
  io = IO.new(fd)
  ary = []
  while (line = io.gets)
    ary << line
  end
  io.close
end
puts "gets: #{Time.now - t1}sec"

t1 = Time.now
10000.times do
  fd = IO.sysopen("AUTHORS")
  io = IO.new(fd)
  io.read
  io.close
end
puts "read: #{Time.now - t1}sec"
  • iij/mruby ... gets: 0.8sec, read: 0.23sec
  • mruby/mruby + mruby-io ... gets: 1.8sec, read: 0.28sec
  • ruby1.9.3 ... gets: 0.3sec, read: 0.23sec

リファクタリング前後での比較 @ imac

repo gets read
iij/mruby 1.401791sec 0.186041sec
mruby-io before 1.695227sec 0.283898sec
mruby-io after 0.778406sec 0.249566sec
ruby1.9.3 0.287875sec 0.258772sec
Clone this wiki locally