6

私のiisログを分析するだけです(ボーナス:たまたまiislogがASCIIでエンコードされていることを知っていました、errrr..)

これが私のルビーコードです

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.開く

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」は mem のファイル全体を読み取りますが、逆に「open」は常に少し速いのはなぜですか?? Win7 Ruby1.9.3で数回テストしました

4

1 に答える 1

22

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

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

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

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

ソースを掘り下げると、which 呼び出しreadlinesによって実装されます。行をフェッチし、結果を返す配列にプッシュする呼び出し。io_s_readlinesrb_io_readlinesrb_io_readlinesrb_io_getline_1rb_ary_push

each_lineと同じように行をフェッチし、 を使用してロジックに行を生成するrb_io_each_line呼び出しによって実装されます。rb_io_getline_1readlinesrb_yield

each_lineしたがって、配列のサイズ変更やコピーの問題のために、行の結果を拡大する配列に格納する必要はありません。

于 2013-03-28T10:41:56.247 に答える