From: "Glass_saga (Masaki Matsushita)" Date: 2012-06-11T22:25:59+09:00 Subject: [ruby-dev:45720] [ruby-trunk - Feature #6440] 引数にIOを渡した場合のMarshal.loadにバッファを持たせたい Issue #6440 has been updated by Glass_saga (Masaki Matsushita). File patch2.diff added ささださんの案を元に読み過ぎないような先読み機構を考えてみました。 ささださんが指摘するように、n要素のArrayをm番目まで読んだところでバッファが不足した場合には、 少なくともn - m バイトは先読みできる事が保証されます。 Arrayがネストしている場合には、最も内側にあるArrayに関してはn - m バイト読む事ができますが、 そのひとつ外側のArrayに関しては、最も内側のArrayについて先読みした時点で既に1要素読んでしまっているので、 n - m - 1 バイト先読みする事ができます。それより外側のArrayに関しても同様です。 従って、最も内側のArrayのみn - m バイト先読みする事ができ、それ以外はn - m - 1 バイト先読みする事ができます。 今回は、struct load_argにreadableという「少なくとも何バイト先読みできるか」を表すメンバを追加する事にしました。 r_object0()でtypeがARRAYである場合には、arg->readableにlen - 1を足し、1要素読む毎にデクリメントします。 これは、n - m - 1バイトに対応します。 バッファが不足した場合には、arg->readable + 1バイト先読みできます。 arg->readable + 1とするのは、最も内側のArrayに関してだけn - mバイト先読みする事に相当します。 HashやStructに関しても同様の処理を行なっています。 ただし、これらは1要素に少なくとも2バイトは必要なのでarg->readableには(len - 1) * 2を足し、1要素読む毎に2を引いています。 最も内側のHashやStructに関しては(n - m) * 2バイト、つまりarg->readable + 2バイトまで読めるのですが、 1バイト多く先読みする為だけにr_byteやr_bytes0にtypeを渡す必要もないと思ったので、そこまではやっていません。 [ruby-dev:45637]と同様のベンチマークを実行したところ、以下の結果となりました。 trunk(r35983) user system total real 0.560000 0.030000 0.590000 ( 0.601471) proposed: user system total real 0.090000 0.010000 0.100000 ( 0.113099) patchを添付します。 ---------------------------------------- Feature #6440: 引数にIOを渡した場合のMarshal.loadにバッファを持たせたい https://bugs.ruby-lang.org/issues/6440#change-27165 Author: Glass_saga (Masaki Matsushita) Status: Assigned Priority: Normal Assignee: nobu (Nobuyoshi Nakada) Category: core Target version: 2.0.0 =begin 現在の(({Marshal.load}))では、引数に(({IO}))を渡すと(({IO#getbyte}))や(({IO#read}))で当座に必要な部分のみの読み出しを繰り返すので 大量のメソッド呼び出しが発生し、そのコストが無視できません。 そこで、引数に(({IO}))を渡した場合の(({Marshal.load}))にバッファを持たせる事を提案します。 require 'benchmark' require 'tempfile' ary = Array.new(1000){ "hoge" } file = Tempfile.new("foo") Marshal.dump(ary, file) Benchmark.bm do |x| x.report do 100.times do file.rewind Marshal.load(file) end end end file.close 上記のベンチマークでバッファを持つようにしたrubyとtrunkを比較したところ、以下の結果となりました。 trunk(r35660): user system total real 1.880000 0.000000 1.880000 ( 1.874681) proposed: user system total real 0.180000 0.000000 0.180000 ( 0.178556) patchを添付します。 =end -- http://bugs.ruby-lang.org/