2013-03-28 1 views
6

はちょうど私のIISログを分析する:ルビーでは、file.readlines.eachはfile.open.each_lineより速くないのですが、なぜですか?

は、ここに私のRubyコードです(BONUS ... IISLOGがerrrr、ASCIIでエンコードされていることを知ることが起こった)

1.readlines

Dir.glob("*.log").each do |filename| 
    File.readlines(filename,:encoding => "ASCII").each do |line| 
    #comment line 
    if line[0] == '#' 
     next 
    else 
     line_content = line.downcase 
     #just care about first one 
     matched_keyword = keywords.select { |e| line_content.include? e }[0] 
     total_count += 1 if extensions.any? { |e| line_content.include? e } 
     hit_count[matched_keyword] += 1 unless matched_keyword.nil? 
    end 
    end 
end 

2.open逆に少し速く、常に "開く" なぜ

Dir.glob("*.log").each do |filename| 
    File.open(filename,:encoding => "ASCII").each_line do |line| 
    #comment line 
    if line[0] == '#' 
     next 
    else 
     line_content = line.downcase 
     #just care about first one 
     matched_keyword = keywords.select { |e| line_content.include? e }[0] 
     total_count += 1 if extensions.any? { |e| line_content.include? e } 
     hit_count[matched_keyword] += 1 unless matched_keyword.nil? 
    end 
    end 
end 

"readlines" read the whole file in mem、?? Win7 Ruby1.9で数回試しました。

答えて

18

readlinesopen.each_lineの両方のファイルを一度だけ読みました。 RubyはIOオブジェクトのバッファリングを行うため、毎回ディスクからブロック(たとえば64KB)のデータを読み込み、ディスクの読み込みコストを最小限に抑えます。ディスク読み込みステップには時間のかかる差異はほとんどありません。

readlinesを呼び出すと、Rubyは空の配列[]を作成し、ファイル内容の行を繰り返し読み込み、配列にプッシュします。最後に、ファイルのすべての行を含む配列を返します。

each_lineを呼び出すと、Rubyはファイルの内容の行を読み込み、ロジックに出力します。この行の処理が終了すると、rubyは別の行を読み込みます。ファイルに内容がなくなるまで繰り返し行を読み込みます。

2つの方法の違いは、readlinesが配列に行を追加する必要があることです。ファイルが大きければ、Rubyは基本配列(Cレベル)を複製​​して、そのサイズを1回以上拡大する必要があります。

readlinesは、io_s_readlinesrb_io_readlines)を呼び出して実装されています。 rb_io_readlinesは、行をフェッチするためにrb_io_getline_1を呼び出し、戻り値の配列に結果をプッシュするためにrb_ary_pushを呼び出します。

each_lineはちょうどreadlinesのような行をフェッチし、rb_yieldとあなたのロジックにラインを得るためにrb_io_getline_1を呼び出しrb_io_each_lineによって実装されます。

each_lineの配列のサイズが増え、配列のサイズ変更やコピーの問題が発生しないため、結果を格納する必要はありません。

関連する問題