【问题标题】:Processing web pages concurrently with Ruby使用 Ruby 同时处理网页
【发布时间】:2014-12-05 18:21:48
【问题描述】:

我正在尝试使用 ruby​​ Thread 处理给定 URL 数组的不同页面的内容。但是,在尝试打开 URL 时,我总是收到此错误:#<SocketError: getaddrinfo: Name or service not known>

这就是我尝试的方式:

sites.each do |site|
    threads << Thread.new(site) do |url|
        puts url
        #web = open(url) { |i| i.read } # same issue opening the web this way
        web = Net::HTTP.new(url, 443).get('/', nil)
        lock.synchronize do
            new_md5[sites_hash[url]] = Digest::MD5.hexdigest(web)
        end
    end
end

sites 是 URL 数组。

相同的程序,但顺序可以正常工作:

sites.each { |site|
    web = open(site) { |i| i.read }
    new_md5 << Digest::MD5.hexdigest(web)
}

有什么问题?

【问题讨论】:

  • 呃。您要为必须处理的每个站点打开一个线程吗?如果您有 10,000 个站点怎么办?设置线程数量限制,将sites变成一个队列,让每个线程删除一个站点,处理它并获取另一个站点。如果队列中没有更多站点,则线程可以退出。
  • 我有java并发的经验,这里列表只有5个线程...我只是想知道为什么我在打开网络时遇到这个问题
  • 什么版本的 Ruby?

标签: ruby concurrency parallel-processing


【解决方案1】:

呃。您要为必须处理的每个站点打开一个线程吗?如果您有 10,000 个站点怎么办?

相反,设置线程数限制,将sites 转换为Queue,并让每个线程删除一个站点,对其进行处理并获取另一个站点。如果队列中没有更多站点,则线程可以退出。

队列文档中的示例将帮助您入门。

不要使用get总是 检索整个正文,而是使用一个跟踪页面上次处理时间的后备数据库。使用head 来检查页面从那时起是否已更新。如果有,然后执行get。这将减少您和他们的带宽和 CPU 使用率。这一切都是为了成为一个好的网络公民,并与其他人的玩具玩得很好。如果你玩得不好,他们可能不会再让你和他们一起玩了。

我已经编写了数百个蜘蛛和站点分析器。我建议您应该始终拥有一个后备数据库,并使用它来跟踪您将要阅读的网站、上次阅读它们的时间、您上次尝试获取页面时它们是向上还是向下,以及你试图联系他们多少次,他们都失败了。 (最后一点是这样您就不会试图将代码的头撞到墙上试图到达死/停机站点。)

我有一个阅读页面的 75 线程应用程序。每个线程将他们的发现写入数据库,如果需要处理页面,则将 HTML 写入另一个表中的记录。然后一个应用程序读取该表并进行处理。单个应用程序很容易保持领先于 75 个线程,因为它们正在处理缓慢的互联网。

使用后端数据库的最大优势在于,您的代码可以关闭,并且如果您编写正确,它会在下一个要处理的站点的同一位置继续运行。您也可以轻松扩展它以在多个主机上运行。


关于找不到主机:

我在您的代码中看到的一些内容:

其中任何一个都可以解释为什么使用 open 有效,但您的代码却无效。 (我假设您将 OpenURI 与单线程代码结合使用,尽管您没有显示它,因为 open 本身不知道如何处理 URL。)


一般来说,我建议使用Typhoeus and Hydra 来并行处理大量网站。 Typhoeus 还将为您处理重定向,并允许您使用 head 请求。您还可以设置同时处理多少个请求(并发)并自动处理重复的请求(记忆),这样多余的 URL 就不会受到冲击。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-18
    • 2017-11-20
    • 1970-01-01
    • 2011-06-14
    • 2021-12-30
    • 2012-05-22
    • 1970-01-01
    • 2019-10-20
    相关资源
    最近更新 更多