异步发出多个HTTP请求

NVI*_*NVI 11 ruby concurrency asynchronous fiber

require 'net/http'

urls = [
  {'link' => 'http://www.google.com/'},
  {'link' => 'http://www.yandex.ru/'},
  {'link' => 'http://www.baidu.com/'}
]

urls.each do |u|
  u['content'] = Net::HTTP.get( URI.parse(u['link']) )
end

print urls
Run Code Online (Sandbox Code Playgroud)

此代码以同步方式工作.第一个请求,第二个,第三个.我想异步发送所有请求并urls在完成所有请求后打印.

最好的办法是什么?纤维是否适合这种情况?

Aug*_*aas 15

这是使用线程的示例.

require 'net/http'

urls = [
  {'link' => 'http://www.google.com/'},
  {'link' => 'http://www.yandex.ru/'},
  {'link' => 'http://www.baidu.com/'}
]

urls.each do |u|
  Thread.new do
    u['content'] = Net::HTTP.get( URI.parse(u['link']) )
    puts "Successfully requested #{u['link']}"

    if urls.all? {|u| u.has_key?("content") }
      puts "Fetched all urls!"
      exit
    end
  end
end

sleep
Run Code Online (Sandbox Code Playgroud)


Jos*_*man 15

我刚刚看到这一年,一年又一段时间,但希望对于一些Google员来说还不算太晚......

Typhoeus是迄今为止最好的解决方案.它以非常优雅的方式包装了libcurl.你可以设置max_concurrency最多200左右而不会窒息.

关于超时,如果你传递Typhoeus一个:timeout标志,它只会注册一个超时作为响应...然后你甚至可以把请求放回另一个九头蛇,如果你愿意再试一次.

这是用Typhoeus重写的程序.希望这有助于以后遇到此页面的任何人!

require 'typhoeus'

urls = [
  'http://www.google.com/',
  'http://www.yandex.ru/',
  'http://www.baidu.com/'
]

hydra = Typhoeus::Hydra.new

successes = 0

urls.each do |url|
    request = Typhoeus::Request.new(url, timeout: 15000)
    request.on_complete do |response|
        if response.success?
            puts "Successfully requested " + url
            successes += 1
        else
            puts "Failed to get " + url
        end
    end
    hydra.queue(request)
end

hydra.run 

puts "Fetched all urls!" if successes == urls.length
Run Code Online (Sandbox Code Playgroud)


小智 6

我写了一篇关于这个主题的深入博客文章,其中包含一个与 8 月发布的答案有些相似的答案 - 但有一些关键区别:1) 跟踪“线程”数组中的所有线程引用。2) 在程序结束时使用“join”方法来占用线程。

require 'net/http'

# create an array of sites we wish to visit concurrently.
urls = ['link1','link2','link3']  
# Create an array to keep track of threads.
threads = []

urls.each do |u|  
  # spawn a new thread for each url
  threads << Thread.new do
  Net::HTTP.get(URI.parse(u))
    # DO SOMETHING WITH URL CONTENTS HERE
    # ...
    puts "Request Complete: #{u}\n"
  end
end

# wait for threads to finish before ending program.
threads.each { |t| t.join }

puts "All Done!"  
Run Code Online (Sandbox Code Playgroud)

完整教程(和一些性能信息)可在此处获得:https : //zachalam.com/performing-multiple-http-requests-asynchronously-in-ruby/


klo*_*ffy 1

这可以通过 C 库cURL来完成。该库存在一个ruby​​ 绑定,但它似乎不支持开箱即用的此功能。但是,看起来有一个补丁添加/修复了它(页面上提供了示例代码)。我知道这听起来不太好,但如果没有更好的建议,可能值得一试。