这就是我想要完成的事情。假设我有100,000个url存储在数据库中,我想检查每个URL的http状态并存储该状态。我希望能够在相当短的时间内同时完成这项工作。
我想知道这样做的最佳方法是什么。我曾考虑过与工人/消费者或某种模型一起使用某种队列,但我没有足够的经验来了解在这种情况下哪种方法最有效。
想法?
答案 0 :(得分:4)
看一下非常有能力的Typhoeus and Hydra组合。这两者使得同时处理多个URL变得非常容易。
“Times”示例可让您快速启动并运行。在on_complete
块中,将代码写入数据库。您可以使用一个线程来构建和维护一个健康级别的排队请求,或者将一组号码排队,让它们全部运行完成,然后循环另一个组。这取决于你。
Paul Dix,原作者,talked about his design goals在他的博客上。
这是我编写的用于下载存档邮件列表的示例代码,因此我可以进行本地搜索。如果人们开始运行代码,我故意删除URL以防止网站遭受DOS攻击:
#!/usr/bin/env ruby
require 'nokogiri'
require 'addressable/uri'
require 'typhoeus'
BASE_URL = ''
url = Addressable::URI.parse(BASE_URL)
resp = Typhoeus::Request.get(url.to_s)
doc = Nokogiri::HTML(resp.body)
hydra = Typhoeus::Hydra.new(:max_concurrency => 10)
doc.css('a').map{ |n| n['href'] }.select{ |href| href[/\.gz$/] }.each do |gzip|
gzip_url = url.join(gzip)
request = Typhoeus::Request.new(gzip_url.to_s)
request.on_complete do |resp|
gzip_filename = resp.request.url.split('/').last
puts "writing #{gzip_filename}"
File.open("gz/#{gzip_filename}", 'w') do |fo|
fo.write resp.body
end
end
puts "queuing #{ gzip }"
hydra.queue(request)
end
hydra.run
在我几年前的MacBook Pro上运行代码,在不到20秒的时间内通过无线连接到76个文件,总共11MB。如果您只做HEAD
次请求,那么您的吞吐量会更好。你会想要搞乱并发设置,因为有一个点,让更多的并发会话只会减慢你的速度并且不必要地使用资源。
我给它八分之一;这是一个很棒的节拍,我可以跳舞。
编辑:
检查删除网址时,您可以使用HEAD请求,也可以使用If-Modified-Since
进行GET。他们可以为您提供可用于确定网址新鲜度的回复。
答案 1 :(得分:1)
我没有在Ruby中做任何多线程,只有Java,但看起来非常简单:http://www.tutorialspoint.com/ruby/ruby_multithreading.htm
根据你的描述,你不需要任何队列和工人(嗯,我相信你也可以这样做,但我怀疑你会得到很多好处)。只需在几个线程之间划分您的URL,让每个线程执行每个块并使用结果更新数据库。例如,创建100个线程,并为每个线程提供1000个数据库行的处理范围。
如果您更愿意处理流程而不是线程,您甚至可以创建100个单独的流程并将它们作为参数提供。
要获取URL状态,我认为你做了一个HTTP HEAD请求,我猜在ruby中是http://apidock.com/ruby/Net/HTTP/request_head。
答案 2 :(得分:0)
work_queue gem是在应用程序中异步和并发执行任务的最简单方法。
wq = WorkQueue.new 10
urls.each do |url|
wq.enqueue_b do
response = Net::HTTP.get_response(uri)
puts response.code
end
end
wq.join