这是我想要实现的目标。假设我有100,000个urls存储在数据库中,我想检查每个urls的http状态并存储该状态。我希望能够在相当短的时间内同时做到这一点。
我想知道做这件事最好的方法是什么。我考虑过对工作人员/消费者使用某种类型的队列或某种事件模型,但我真的没有足够的经验来了解在这种情况下最好的工作方式。
想法?
发布于 2011-01-29 06:49:01
看看功能非常强大的Typhoeus and Hydra组合。这两种方法使得并发处理多个URL变得非常容易。
"Times“示例应该能让您快速上手并运行。在on_complete块中,将您的代码写入到DB中。您可以使用线程来构建和维护处于健康状态的队列请求,或者将队列排成一定数量,让它们都运行到完成,然后循环到另一个组。由你决定。
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在我用了几年的DSL上运行代码,在不到20秒的时间里,通过无线方式传输到MacBook上,获得了76个文件,总大小为11MB。如果你只做HEAD请求,你的吞吐量会更好。你会想要弄乱并发设置,因为有更多的并发会话只会减慢你的速度,并且不必要地使用资源。
我给它打了8分(满分10分);它的节拍很棒,我可以跟着它跳舞。
编辑:
在检查删除URL时,您可以使用HEAD请求,或对If-Modified-Since使用GET。它们可以为您提供响应,您可以使用这些响应来确定URL的新鲜度。
发布于 2011-01-29 05:54:35
我还没有用Ruby语言做过任何多线程的事情,只用Java语言做过,但是看起来很简单:http://www.tutorialspoint.com/ruby/ruby_multithreading.htm
根据您所描述的,您不需要任何队列和工人(嗯,我相信您也可以这样做,但我怀疑您不会获得太多好处)。只需在几个线程之间划分您的urls,让每个线程完成每个块并使用结果更新数据库。例如,创建100个线程,并为每个线程提供1000个数据库行的范围以供处理。
如果您更愿意处理进程而不是线程,您甚至可以创建100个单独的进程,并将行作为参数提供给它们。
要获取URL状态,我认为您需要执行一个HTTP HEAD请求,我猜它在ruby中是http://apidock.com/ruby/Net/HTTP/request_head。
发布于 2015-06-20 03:22:51
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.joinhttps://stackoverflow.com/questions/4832956
复制相似问题