В ruby, файл.readlines.каждый не быстрее файла.открыть.каждая строчка, почему?

просто проанализировать мой журнал 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, почему "открыть" всегда немного быстрее наоборот?? Я тестировал его пару раз на Win7 Ruby1.9.3

1 ответов


и readlines и open.each_line читать файл только один раз. И Ruby будет делать буферизацию на объектах ввода-вывода, поэтому он будет читать данные блока (например, 64KB) с диска каждый раз, чтобы минимизировать затраты на чтение диска. На шаге чтения диска должна быть небольшая разница во времени.

когда вы называете readlines, Ruby создает пустой массив [] и неоднократно считывает строку содержимого файла и помещает ее в массив. И, наконец, он вернет массив, содержащий все строки файл.

когда вы называете each_line, Ruby читает строку содержимого файла и передает ее вашей логике. Когда вы закончили обработку этой строки, ruby читает другую строку. Он многократно считывает строки, пока в файле больше нет содержимого.

разница между двумя методами заключается в том, что readlines необходимо добавить строки в массив. Когда файл большой, Ruby может потребоваться дублировать базовый массив (уровень C), чтобы увеличить его размер на один или несколько раз.

копание в источнике,readlines осуществляется io_s_readlines которых звонки rb_io_readlines. rb_io_readlines звонки rb_io_getline_1 чтобы получить линию и rb_ary_push для ввода результата в возвращаемый массив.

each_line осуществляется rb_io_each_line которых звонки rb_io_getline_1 чтобы получить строку так же, как readlines и дайте строку вашей логике с rb_yield.

таким образом, нет необходимости хранить результаты строки в растущем массиве для each_line, нет изменение размера массива, проблема копирования.