1

假设我有一个包含 1000 个唯一 url 的列表,我需要打开每一个,并且assert页面上的内容就在那里。按顺序执行此操作显然是一个糟糕的选择,因为大多数情况下程序将处于空闲状态,只是等待响应。因此,添加到线程池中,每个工作人员从 main 读取Queue,并打开一个 url 进行检查。我的问题是,我要把游泳池弄多大?它是基于我的网络带宽还是其他一些指标?是否有任何经验法则,或者只是为了找到有效尺寸而反复试验?

这更像是一个理论问题,但这是我正在使用的代码的基本轮廓。

if __name__ == '__main__':
    #get the stuff I've already checked
    ID = 0
    already_checked = [i[ID] for i in load_csv('already_checked.csv')]

    #make sure I don't duplicate the effort
    to_check = load_csv('urls_to_check.csv')
    links = [url[:3] for url in to_check if i[ID] not in already_checked]

    in_queue = Queue.Queue()
    out_queue = Queue.Queue()

    threads = []
    for i in range(5):
        t = SubProcessor(in_queue, out_queue)
        t.setDaemon(True)
        t.start()
        threads.append(t)

    writer = Writer(out_queue)
    writer.setDaemon(True)
    writer.start()

    for link in links:
        in_queue.put(link)
4

2 回答 2

1

您最好的选择可能是编写一些代码,使用您指定的线程数运行一些测试,并查看有多少线程产生最佳结果。有太多变量(处理器速度、总线速度、线程开销、内核数量和代码本身的性质)让我们无法猜测。

于 2013-04-29T17:03:49.063 回答
0

我的经验(使用 .NET,但它应该适用于任何语言)是 DNS 解析最终成为限制因素。我发现最多可以支持 15 到 20 个并发请求。DNS 解析通常非常快,但有时可能需要数百毫秒。如果没有一些自定义 DNS 缓存或其他快速解决问题的方法,我发现它平均大约 50 毫秒。

如果您可以进行多线程 DNS 解析,那么在现代硬件(四核机器)上肯定可以处理 100 个或更多并发请求。您的操作系统如何处理这么多单独的线程完全是另一个问题。但是,正如您所说,这些线程大多只在等待响应。另一个考虑因素是这些线程正在做多少工作。如果它只是下载一个页面并寻找特定的东西,100 个线程可能在合理范围内。前提是“查找”不仅仅涉及解析 HTML 页面。

其他注意事项涉及您正在访问的唯一域的总数。如果这 1,000 个唯一 URL 都来自不同的域(即 1,000 个唯一域),那么您将遇到最坏的情况:每个请求都需要 DNS 解析(缓存未命中)。

如果这 1,000 个 URL 仅代表 100 个域,那么您将只有 100 个缓存未命中。前提是你机器的DNS缓存是合理的。但是,您还有另一个问题:使用多个并发请求访问同一台服务器。如果您发出许多(有时“许多”被定义为“两个或更多”)并发请求,某些服务器会非常不高兴。或者短时间内请求过多。因此,您可能必须编写代码来防止对同一服务器的多个或超过 X 个并发请求。它可能会变得复杂。

防止多请求问题的一种简单方法是按域对 URL 进行排序,然后确保来自同一域的所有 URL 都由同一线程处理。从性能的角度来看,这并不理想,因为您经常会发现一两个域的 URL 比其他域多得多,并且您最终会发现大多数线程都结束了,而只有少数线程正在阻塞繁忙的域。您可以通过检查数据并相应地分配线程的工作项来缓解这些问题。

于 2013-04-29T17:04:21.333 回答