ruby - 为什么 Ruby 中的 curl 比命令行 curl 慢?

标签 ruby http curl download curb

我正在尝试下载超过 100 万页(以序列 ID 结尾的 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
}

我尝试下载 8000 页样本。使用上面的代码时,我在 2 分钟内得到 1000。当我将所有 URL 写入文件并在 shell 中执行时:

cat list | xargs curl

我在两分钟内生成了所有 8000 页。

问题是,我需要将其包含在 ruby​​ 代码中,因为还有其他监控和处理代码。

我试过:

  • Curl::Multi - 它以某种方式更快,但遗漏了 50-90% 的文件(不下载它们并且没有给出原因/代码)
  • 使用 Curl::Easy 的多线程 - 与单线程的速度大致相同

为什么重用 Curl::Easy 比后续的命令行 curl 调用慢,我怎样才能让它更快?或者我做错了什么?

我宁愿修复我的下载管理器代码,也不愿以不同的方式为这种情况进行下载。

在此之前,我调用了命令行 wget,我为它提供了一个包含 URL 列表的文件。然而,并不是所有的错误都得到处理,而且在使用 URL 列表时也不可能为每个 URL 单独指定输出文件。

在我看来,最好的方法是使用多线程和系统调用“curl”命令。但为什么我可以在 Ruby 中直接使用 Curl?

下载管理器的代码在这里,如果有帮助的话:Download Manager (我玩过超时,从不设置它到各种值,它似乎没有帮助)

感谢任何提示。

最佳答案

这可能是适合 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 }
  # ...
}

关于ruby - 为什么 Ruby 中的 curl 比命令行 curl 慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2856305/

相关文章:

java - Java 中的下载管理器

php - 从 php 启动 phantomjs 服务器并等待它的响应

bash - 使用 CURL 下载文件并查看标题和状态代码

gcc - 对 `__ctype_b_loc' 等的 undefined reference

ruby - 提交时生成文档

java - 在 Android 上使用 http 请求 POST xml 文件

ruby-on-rails - ruby rails : what does "equals" symbol mean as a parameter?

java - 读取HTTP InputStream的麻烦

ruby - 如何仅比较两个 Time 对象到小时

Ruby Lambda 与 Proc LocalJumpError