2010-01-24 178 views
8
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

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

什么是最好的办法呢?纤维是否适合这一点?

回答

1

这可以通过C库cURL完成。该库存在ruby binding,但它似乎并不支持该功能。但是,看起来好像有a patch添加/修复它(示例代码在页面上可用)。我知道这听起来不太好,但如果没有更好的建议,可能值得一试。

0

你可以有一个不同的线程执行net :: HTTP.get的每一个。等待所有线程完成。

BTW打印网址将打印链接和内容。

12

这是一个使用线程的例子。

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 
+0

好像它的工作原理。但如果15秒后服务器没有响应,如何终止线程? – NVI 2010-01-25 09:13:05

+1

你可以使用'Timeout.timeotu(20)do .... end'。然而,这引发了一个错误,因此您需要对程序流进行一些处理,并且有一种标记方式来标记请求已完成,而不是检查是否存在“内容”键。 – 2010-01-25 11:11:27

+0

Ruby的Net :: HTTP线程安全吗? – Daniel777 2017-05-16 18:38:53

11

我刚刚看到这一点,一年稍晚,但希望不要太晚了一些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 
0

work_queue宝石在你的应用程序异步并同时执行任务的最简单方法。

wq = WorkQueue.new 2 # Limit the maximum number of simultaneous worker threads 

urls.each do |url| 
    wq.enqueue_b do 
    response = Net::HTTP.get_response(url) 
    # use the response 
    end 
end 

wq.join # All requests are complete after this 
1

我已经写了深入的博客文章关于这个话题,其中包括一个答案,有点类似于一个八月发布的 - 但有一些关键的不同: 1)保持所有线程引用的轨道“线程”数组。 2)使用“连接”方法在程序结束时绑定线程。

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!" 

完整的教程(以及一些性能信息),请访问:https://zachalam.com/performing-multiple-http-requests-asynchronously-in-ruby/