【问题标题】:Python Socket and Thread pooling, how to get more performance?Python Socket 和线程池,如何获得更多性能?
【发布时间】:2011-07-07 12:42:19
【问题描述】:

我正在尝试实现一个基本库来发出 HTTP GET 请求。我的目标是通过 socket 连接 接收数据 - 提高 性能 的简约设计 - 线程、线程池的使用。

我有一堆按它们的主机名分组的链接,所以这里有一个输入 URL 的简单演示:

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

由于性能问题,我打算使用套接字。我打算使用一些保持连接的套接字(如果可能的话,通常是这样)并发出 HTTP GET 请求。这个想法来自 urllib 在连续请求上的低性能,然后我遇到了 urllib3,然后我意识到它使用了 httplib,然后我决定尝试套接字。所以这是我到目前为止所完成的:

GETSocket class, SocketPool class, ThreadPool and Worker classes

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 here 的信息,但我不知道如何使用与提供的 class HTTPClient(asyncore.dispatcher) 相同的套接字连接。

另外一点,我不知道我用的是阻塞还是非阻塞socket,哪个对性能更好或者如何实现哪个。

请具体说明您的经验,我不打算导入另一个库只做 HTTP GET,所以我想编写自己的小库。

任何帮助表示赞赏,谢谢。

【问题讨论】:

  • 多线程并不能真正使 HTTP GET 操作更快。您需要使用多个进程。
  • 我知道,我的意思是同时从列表中请求和接收 5 个链接可以更快地检索列表中的所有链接。从这个意义上说,带宽是更快完成它的上限。进程或线程——它们最终提供的不一样吗?
  • "带宽是上限" True。但是线程都共享一个 OS 进程的 I/O 资源。多个操作系统进程不共享其 I/O 资源。
  • 使用多处理或线程是我的意图,我特别关注如何改进我的套接字交互。但我可以使用这个想法,你能告诉我它会改进什么吗?由于我将在获取所有数据后处理检索到的数据,共享或不共享 I/O 资源是否会成为问题?
  • 我不想这么说,但是如果您遇到性能问题,那么 httplib 不太可能是问题所在,它是套接字库之上的一个非常薄的层。如果您可以提供更多关于性能问题的解释,则可能可以解决根本原因,而不是分支编写自己的 http lib。

标签: python multithreading sockets threadpool http-get


【解决方案1】:

这样做。

使用multiprocessinghttp://docs.python.org/library/multiprocessing.html.

  1. 编写一个worker Process,它将所有的URL 放入Queue

  2. 编写一个worker Process,它从Queue 获取URL 并执行GET,保存文件并将文件信息放入另一个队列。您可能需要此Process 的多个副本。您必须尝试找出正确的数字是多少。

  3. 编写一个工作线程Process,它从Queue 读取文件信息并执行您尝试执行的任何操作。

【讨论】:

  • 一个大问题:既然我想重用socket连接,如何与子进程共享这些socket?据我了解,您提到的 Queue 对象是为了获取结果。
  • 每个worker Process 管理它自己的套接字连接。它可以根据需要重用或不重用。重用不会有多大好处,但每个工人 Process 肯定可以重用任何似乎有帮助的东西。
  • 我正在使用 multiprocessing.Pool (Python 3),但我不知道如何使用 Queue。我应该将 Queue 对象作为参数传递,还是应该是全局的?我不断收到奇怪的错误:(
  • 听到“将其作为参数传递”或“是的,全局队列可以工作”就可以了。反正。看看this
  • @Kerem Ulutaş:这是一个单独的问题,不是对这个问题的评论。回答一个单独的问题(在 cmets 中提出)意味着其他人不会找到那个单独的问题或单独的答案。请将单独的问题作为单独的问题发布,以便它得到正确的答案并可以为其他人提供适当的帮助。
【解决方案2】:

我终于找到了一条经过精心挑选的途径来解决我的问题。我的项目使用的是 Python 3,而我唯一的选择是使用 pycurl,所以这让我不得不将我的项目移植回 Python 2.7 系列。

使用 pycurl,我获得了: - 对我的请求的一致响应(实际上我的脚本必须处理至少 10k 个 URL) - 使用 ThreadPool 类,我可以尽可能快地接收响应(接收到的数据稍后处理 - 所以这里不太可能进行多处理)

我首先尝试了 httplib2,我意识到它不像在 Python 2 上那样可靠,通过切换到 pycurl 我失去了缓存支持。

最终结论:当涉及到 HTTP 通信时,可能需要一个像 (py)curl 这样的工具供他使用。它是一种救命稻草,尤其是在处理大量 URL 时(有时为了好玩而尝试:你会从它们那里得到很多奇怪的响应)

谢谢大家的回复。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2021-08-11
  • 1970-01-01
  • 1970-01-01
  • 2014-11-22
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 2019-11-08
相关资源
最近更新 更多