Почему завихрение в Ruby медленнее, чем завихрение командной строки?

Я пытаюсь загрузить страницы больше чем на 1 м (URL, заканчивающиеся идентификатором последовательности). Я реализовал вид многоцелевого менеджера загрузок с настраиваемым количеством потоков загрузки и одного потока обработки. Загрузчик загружает файлы в пакетах:

curl = Curl::Easy.new

batch_urls.each { |url_info|
    curl.url = url_info[:url]
    curl.perform
    file = File.new(url_info[:file], "wb")
    file << curl.body_str
    file.close
    # ... some other stuff
}

Я попытался загрузить образец на 8 000 страниц. При использовании кода выше, я добираюсь 1000 за 2 минуты. Когда я пишу все URL в файл и делаю в оболочке:

cat list | xargs curl

Я генерал все 8 000 страниц за две минуты.

Вещь, мне нужна она, чтобы иметь ее в коде Ruby, потому что существует другой контроль и код обработки.

Я попробовал:

  • Завихрение:: Много - это так или иначе быстрее, но отсутствует, 50-90% файлов (не загружает их и не приводит причины),
  • несколько потоков с Завихрением:: Легкий - вокруг той же скорости как единственная распараллелил

Почему снова используется Завихрение:: Легкий медленнее, чем последующая командная строка завихряются вызовы и как я могу сделать ее быстрее? Или что я делаю неправильно?

Я предпочел бы исправлять свой код менеджера загрузок, чем сделать загрузку для этого случая по-другому.

Перед этим я называл командную строку wget, которому я предоставил файл со списком URL. Howerver, не все ошибки были обработаны, также не было возможно указать выходной файл для каждого URL отдельно при использовании списка URL.

Теперь мне кажется, что лучший способ состоял бы в том, чтобы использовать несколько потоков с системным вызовом для 'завихрений' команды. Но почему, когда я могу использовать непосредственно Вихревой в Ruby?

Код для менеджера загрузок здесь, если он мог бы помочь: Менеджер загрузок (я играл с тайм-аутами от не установленного это к различным значениям, это не казалось справкой),

Любые подсказки ценятся.

7
задан Stiivi 18 May 2010 в 10:20
поделиться

4 ответа

Это может быть подходящая задача для Typhoeus

Примерно так (непроверено):

require 'typhoeus'

def write_file(filename, data)
    file = File.new(filename, "wb")
    file.write(data)
    file.close
      # ... some other stuff
end

hydra = Typhoeus::Hydra.new(:max_concurrency => 20)

batch_urls.each do |url_info|
    req = Typhoeus::Request.new(url_info[:url])
    req.on_complete do |response|
      write_file(url_info[:file], response.body)
    end
    hydra.queue req
end

hydra.run

Если задуматься, у вас могут возникнуть проблемы с памятью из-за огромных количество файлов. Один из способов предотвратить это - никогда не сохранять данные в переменной, а вместо этого передавать их напрямую в файл. Для этого вы можете использовать em-http-request .

EventMachine.run {
  http = EventMachine::HttpRequest.new('http://www.website.com/').get
  http.stream { |chunk| print chunk }
  # ...
}
5
ответ дан 7 December 2019 в 03:12
поделиться

Сначала позвольте мне сказать, что я почти ничего не знаю о Ruby.

Я точно знаю, что Ruby - это интерпретируемый язык; неудивительно, что он медленнее, чем сильно оптимизированный код, скомпилированный для конкретной платформы. В каждой файловой операции, вероятно, будут проверки, которых нет у curl . «Еще кое-что» еще больше замедлит работу.

Вы пробовали профилировать свой код, чтобы увидеть, на что тратится большая часть времени?

0
ответ дан 7 December 2019 в 03:12
поделиться

Итак, если вы не установите обработчик on_body, то curb буферизует загрузку. Если вы загружаете файлы, вам следует использовать обработчик on_body. Если вы хотите загрузить несколько файлов с помощью Ruby Curl, попробуйте интерфейс Curl :: Multi.download.

require 'rubygems'
require 'curb'

urls_to_download = [
  'http://www.google.com/',
  'http://www.yahoo.com/',
  'http://www.cnn.com/',
  'http://www.espn.com/'
]
path_to_files = [
  'google.com.html',
  'yahoo.com.html',
  'cnn.com.html',
  'espn.com.html'
]

Curl::Multi.download(urls_to_download, {:follow_location => true}, {}, path_to_files) {|c,p|}

Если вы хотите просто загрузить один файл.

Curl::Easy.download('http://www.yahoo.com/')

Вот хороший ресурс: http://gist.github.com/405779

3
ответ дан 7 December 2019 в 03:12
поделиться

Стиви,

есть ли вероятность, что Net :: HTTP будет достаточно для простой загрузки HTML-страниц?

0
ответ дан 7 December 2019 в 03:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: