0

这就是我想要完成的事情。假设我有 100,000 个 URL 存储在数据库中,我想检查每个 URL 的 http 状态并存储该状态。我希望能够在相当短的时间内同时执行此操作。

我想知道最好的方法是什么。我考虑过使用某种队列与工人/消费者或某种事件模型,但我真的没有足够的经验来知道在这种情况下什么最有效。

想法?

4

3 回答 3

4

看看非常强大的Typhoeus 和 Hydra组合。两者使得同时处理多个 URL 变得非常容易。

Times ”示例应该让您快速启动并运行。在on_complete块中放置您的代码以将您的状态写入数据库。您可以使用线程来构建和维护处于健康级别的排队请求,或者排队设置一个数字,让它们全部运行到完成,然后循环另一个组。由你决定。

原作者 Paul Dix在他的博客上谈到了他的设计目标。

这是我为下载存档邮件列表而编写的一些示例代码,以便进行本地搜索。如果人们开始运行代码,我故意删除了该 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 秒的时间内通过无线到 DSL 提取了 76 个文件,总计 11MB。如果你只做HEAD请求,你的吞吐量会更好。你会想要弄乱并发设置,因为有更多的并发会话只会减慢你的速度并不必要地使用资源。

我给它 8 分(满分 10 分);它的节拍很棒,我可以跟着它跳舞。


编辑:

检查删除 URL 时,您可以使用 HEAD 请求或带有If-Modified-Since. 他们可以为您提供可用于确定 URL 新鲜度的响应。

于 2011-01-28T22:49:00.543 回答
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

于 2011-01-28T21:54:35.063 回答
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
于 2015-06-19T19:22:51.300 回答