Python套接字与线程池,如何提升性能?

3 投票
2 回答
2975 浏览
提问于 2025-04-16 21:01

我正在尝试实现一个基本的库,用来发送HTTP GET请求。我的目标是通过套接字连接来接收数据,设计尽量简单,以提高性能,并且能够与线程和线程池一起使用。

我有一堆链接,我根据它们的主机名进行分组,下面是一些输入网址的简单示例:

hostname1.com - 500 links
hostname2.org - 350 links
hostname3.co.uk - 100 links
...

我打算使用套接字是因为性能问题。我计划使用一些保持连接的套接字(如果可能的话,通常是可以的),并发送HTTP GET请求。这个想法源于urllib在连续请求时的低性能,后来我遇到了urllib3,发现它使用了httplib,然后我决定尝试使用套接字。所以到目前为止,我完成了以下内容:

GETSocket类、SocketPool类、ThreadPool和Worker类

GETSocket类是Python的httplib的一个简化版,只支持“HTTP GET”。

我这样使用这些类:

sp = Comm.SocketPool(host,size=self.poolsize, timeout=5)
for link in linklist:
    pool.add_task(self.__get_url_by_sp, self.count, sp, link, results)
    self.count += 1
    pool.wait_completion()
    pass

__get_url_by_sp函数是一个包装器,它调用sp.urlopen并将结果保存到results列表中。我使用一个包含5个线程的池,并且有一个包含5个GETSocket类的套接字池。

我想知道,还有没有其他方法可以提高这个系统的性能?

我读过关于asyncore的内容在这里,但我不太明白如何使用class HTTPClient(asyncore.dispatcher)来共享同一个套接字连接。

还有一点,我不知道我使用的是阻塞套接字还是非阻塞套接字,哪种对性能更好,或者如何实现其中一种。

请具体分享你的经验,我不打算导入其他库来仅仅做HTTP GET,所以我想自己编写一个小库。

任何帮助都非常感谢,谢谢。

2 个回答

3

这样做:

使用 multiprocessing。可以查看这个链接了解更多信息:http://docs.python.org/library/multiprocessing.html

  1. 写一个工作进程 Process,把所有的URL放到一个 Queue(队列)里。

  2. 写另一个工作进程 Process,从 Queue 中取出一个URL,进行GET请求,保存文件,并把文件信息放到另一个队列里。你可能需要多个这样的 Process。你需要尝试一下,找出合适的数量。

  3. 再写一个工作进程 Process,从 Queue 中读取文件信息,执行你想要做的操作。

2

我终于找到了解决我问题的好办法。我在我的项目中使用Python 3,但我唯一的选择是用pycurl,这让我不得不把项目转回到Python 2.7版本。

使用pycurl,我得到了以下好处: - 对我的请求有一致的响应(实际上我的脚本需要处理至少1万个网址) - 通过使用ThreadPool类,我能以我系统能承受的最快速度收到响应(收到的数据会稍后处理,所以这里不太适合多进程处理)

我最开始尝试使用httplib2,但我发现它在Python 2上表现得更稳定,切换到pycurl后,我失去了缓存支持。

最终结论是:在进行HTTP通信时,可能需要像(p)curl这样的工具。这真是个救星,特别是当你需要处理大量网址时(有时候试试,真的会收到很多奇怪的响应)

谢谢大家的回复。

撰写回答