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
。
最好的办法是什么?纤维适合吗?
答案 0 :(得分: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
答案 1 :(得分:14)
我刚刚看到这一年,一年又一段时间,但希望对于一些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
答案 2 :(得分:3)
我写了一篇关于这个主题的深入博客文章,其中包含的答案与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!"
完整的教程(以及一些性能信息)可在此处获取:https://zachalam.com/performing-multiple-http-requests-asynchronously-in-ruby/
答案 3 :(得分:1)
可以使用C库cURL完成此操作。该库的ruby binding存在,但它似乎不支持开箱即用的此功能。但是,看起来有a patch添加/修复它(示例代码在页面上可用)。我知道这听起来不太好,但如果没有更好的建议,可能值得一试。
答案 4 :(得分:1)
借助concurrent-ruby
,您可以同时处理数据:
require 'net/http'
require 'concurrent-ruby'
class Browser
include Concurrent::Async
def render_page(link)
sleep 5
body = Net::HTTP.get( URI.parse(link) )
File.open(filename(link), 'w') { |file| file.puts(body)}
end
private
def filename(link)
"#{link.gsub(/\W/, '-')}.html"
end
end
pages = [
'https://www.google.com',
'https://www.bing.com',
'https://www.baidu.com'
].map{ |link| Browser.new.async.render_page(link) }.map(&:value)
答案 5 :(得分:0)
这取决于你之后的功能。你可以用简单的线程来做到这一点:
请参阅:http://snipplr.com/view/3966/simple-example-of-threading-in-ruby/
答案 6 :(得分:0)
你可以让一个不同的线程执行Net :: HTTP.get中的每一个。并等待所有线程完成。
BTW打印网址将打印链接和内容。
答案 7 :(得分:0)
work_queue gem是在应用程序中异步和并发执行任务的最简单方法。
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