在进行网络编程时,是否有一个经验法则来确定要使用多少线程?

时间:2013-04-29 16:48:15

标签: python multithreading threadpool

假设我有一个包含1000个唯一网址的列表,我需要打开每个网址,并且assert页面上的内容就在那里。顺序执行此操作显然是一个糟糕的选择,因为大多数情况下程序将等待响应而处于空闲状态。因此,添加到线程池中,每个工作者从主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)

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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

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

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

如果这1,000个网址仅代表100个网域,那么您将只有100个缓存未命中。只要您的机器的DNS缓存合理。但是,您还有另一个问题:使用多个并发请求命中同一服务器。如果您将许多(有时“很多”定义为“两个或更多”)并发请求做多,那么某些服务器会非常不满意。或者在很短的时间内请求太多。因此,您可能必须编写代码以防止对同一服务器发出多个或多于X个并发请求。它会变得复杂。

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