(2012/05/18 1:39), Glass_saga (Masaki Matsushita) wrote:
> 現在のMarshalの形式では全体のサイズを知る方法がない為に、バッファを持とうとするとどうしても読み過ぎてしまいます。
> ungetcでは駄目となると、seekが可能なIOに対してのみバッファを持つようにして、最後にIO#seekで辻褄を合わせるというのはどうでしょうか。
> 高速化できるIOの種類が限られてしまいますが、互換性は崩さずに済むと思います。

 面白いですね.少し考えてみました.

# ご提案の「seek が効くもののみ」というのは,要するに File の時は,
# って感じですかねぇ.pipe 的なもの(ソケット等)を使うのとどっちが
# 用途として多いんだろう.


案1)
 でかいオブジェクトをやりとりするのは意識が高い人に違いないので,もっと
意識を高く(低く?),こんな感じで workaround をしてもらう.Marshal した
文字列を Marshal して送る.メモリは食いますが,今時気にするだろうか.

  require 'benchmark'
  require 'tempfile'

  ary = Array.new(10_000){ "hoge" }
  file = Tempfile.new("foo")
  file2 = Tempfile.new("bar")
  Marshal.dump(ary, file)
  Marshal.dump(Marshal.dump(ary), file2)

  Benchmark.bm do |x|
    x.report do
      100.times do
        file.rewind
        Marshal.load(file)
      end
    end
    x.report do
      100.times do
        file2.rewind
        Marshal.load(Marshal.load(file2))
      end
    end
  end

  file.close

ruby 2.0.0dev (2012-05-04 trunk 35535) [i386-mswin32_100]
       user     system      total        real
   6.068000   0.031000   6.099000 (  6.334804)
   0.530000   0.016000   0.546000 (  0.573573)


案2)真面目に先読み機構を入れる.

 n 要素の Array を load する場合,少なくとも n byte 先読み出来ます(と
いうことを調べるために,始めて Marshal フォーマット *1 を見た).m 番目
まで読み進めた段階で先読みしたバッファが不足した場合,n - m byte 先読み
出来ます.ネストしてると面倒になりますが(この情報をスタックで管理して,
一番先読み可能なものを集めて先読み,みたいな).

*1:
http://www.ruby-lang.org/ja/old-man/html/Marshal_A5D5A5A9A1BCA5DEA5C3A5C8.html

 ちょっと,複雑に過ぎるかも.

-- 
// SASADA Koichi at atdot dot net