对于我的应用程序,有多少线程是最佳的?

时间:2009-03-08 04:44:41

标签: python multithreading

我有一个简单的Python网络爬虫。它使用SQLite来存储其输出并保留队列。我想让爬虫程序多线程,以便它可以一次抓取几个页面。我想我会创建一个线程并立即运行该类的几个实例,因此它们都同时运行。但问题是,我应该一次运行多少人?我应该坚持两个吗?我可以走高吗?什么线程的合理限制是什么?请记住,每个线程都会转到网页,下载html,运行一些正则表达式搜索,将它找到的信息存储在SQLite数据库中,然后将下一个网址弹出队列。

7 个答案:

答案 0 :(得分:13)

您可能会发现您的应用程序带宽有限,而非CPU或I / O限制。

因此,添加任意数量的内容,直到性能开始降低。

根据您的网络设置,您可能会遇到其他限制。就像你在ADSL路由器后面一样,并发NAT会话的数量会受到限制,这可能会影响一次发出太多的HTTP请求。制作太多,您的提供商可能会将您视为感染病毒等。

还有一个问题是您要抓取的服务器可以处理多少请求以及您想要加载多少负载。

我只用了一个线程就写了一个爬虫。我花了大约一天的时间来处理我想要的所有信息,大约每两秒一页。我可以更快地完成它,但我认为这对服务器来说不是一个负担。

所以真的没有硬性和快速的答案。假设有一个1-5兆位的连接,我会说你可以很容易地拥有多达20-30个线程而没有任何问题。

答案 1 :(得分:7)

如果您已经有一种简单的方法来提供任意长的URL列表,我会使用一个线程和twisted与延迟信号量或任务合作者。

您极不可能制作比基于扭曲的抓取工具更快或更小的多线程抓取工具。

答案 2 :(得分:3)

制作多个并发进程通常更简单。只需使用subprocess创建尽可能多的Popens,就像你认为有必要同时运行一样。

没有“最佳”数字。通常,当您只运行一个爬虫时,您的PC会花费大量时间等待。多少?很难说。

当您运行少量并发抓取工具时,您会发现他们花费的时间与其相同。您的CPU在各个进程之间切换,在其他进程上填写等待时间。

你运行了一些更大的数字,你会发现整体经过的时间更长,因为现在有更多的事要做,而不是你的CPU可以管理。所以整个过程需要更长时间。

您可以创建一个图表,显示流程如何扩展。在此基础上,您可以平衡流程数量和理想的运行时间。

这样想。

1个爬虫在1分钟内完成它的工作。连续完成100页可能需要100分钟。同时可能需要100个爬虫。假设25个爬虫在50分钟内完成了这项工作。

在运行各种组合并比较结果之前,您不知道什么是最佳的。

答案 3 :(得分:3)

克莱特斯的答案是你想要的答案。

有几个人提出了使用异步I / O的替代解决方案,特别是关注Twisted。如果您决定采用该路由,则另一个解决方案是pycurl,这是libcurl的一个瘦包装器,它是一个广泛使用的URL传输库。 PyCurl的主页有一个“retriever-multi.py”示例,说明如何在大约120行代码中并行获取多个页面。

答案 4 :(得分:1)

你可以更高一点。更高的程度完全取决于您运行此系统的硬件,网络操作后正在进行的处理以及当时机器上正在运行的其他内容。

由于它是用Python编写的(并且被称为“简单”),我将假设你并不完全关心从事物中挤出每一盎司的性能。在这种情况下,我建议在常见的工作条件下运行一些测试,看看它是如何运行的。我估计5-10左右可能是合理的,但这是在黑暗中完全刺伤。

由于您使用的是双核机器,我强烈建议您查看Python multiprocessing module(在Python 2.6中)。它可以让您利用机器上的多个处理器,这将显着提升性能。

答案 5 :(得分:1)

您应该记住的一件事是,某些服务器可能会解释来自同一IP地址的过多并发请求与DoS攻击并中止连接或返回错误页面以获取否则会成功的请求。

因此,将同一服务器的并发请求数限制为相对较低的数量可能是一个好主意(5应该是安全的)。

答案 6 :(得分:0)

在这种情况下不需要线程化。您的程序 I / O绑定而不是CPU绑定。使用套接字上的select()可能会更好地完成网络部分。这减少了创建和维护线程的开销。我没有使用Twisted,但我听说它非常支持异步网络。这将允许您指定要下载的URL并为每个URL注册回调。下载每个回调时,将调用回调,并且可以处理页面。为了允许下载多个站点,而不等待每个站点的处理,可以使用队列创建第二个“工作者”线程。回调会将站点的内容添加到队列中。 “worker”线程将进行实际处理。

正如一些答案中所述,同步下载的最佳数量取决于您的带宽。

我使用一个或两个线程 - 一个用于实际抓取,另一个用一个队列进行处理。