3

我正在尝试解决一个问题,我有很多(大约一万个)URL,并且需要从所有这些 URL 中下载内容。到目前为止,我一直在“链接中的链接:”循环中执行此操作,但是现在花费的时间太长了。我认为是时候实现多线程或多处理方法了。我的问题是,最好的方法是什么?

我知道全局解释器锁,但由于我的问题是网络绑定的,而不是 CPU 绑定的,我认为这不会是一个问题。我需要将数据从每个线程/进程传回主线程/进程。我不需要帮助来实现任何方法(当任何线程完成任务时终止多个线程),我需要关于采用哪种方法的建议。我目前的做法:

data_list = get_data(...)
output = []
for datum in data:
    output.append(get_URL_data(datum))
return output

没有其他共享状态。

我认为最好的方法是创建一个包含所有数据的队列,并从输入队列中弹出几个工作线程,获取 URL 数据,然后推送到输出队列。

我对吗?有什么我想念的吗?这是我第一次用任何语言实现多线程代码,我知道这通常是一个难题。

4

3 回答 3

5

对于您的特定任务,我会推荐一个multiprocessing worker pool。您只需定义一个池并告诉它您想要使用多少个进程(默认情况下每个处理器核心一个)以及您想要在每个工作单元上运行的功能。然后,您准备好列表中的每个工作单元(在您的情况下,这将是一个 URL 列表)并将其提供给工作池。

您的输出将是原始数组中每个工作项的工作函数的返回值列表。所有很酷的多处理优点都将在后台发生。当然还有其他使用工作池的方法,但这是我最喜欢的一种。

快乐的多处理!

于 2012-07-24T20:03:54.457 回答
2

像这样执行 IO 绑定任务的最快和最有效的方法是异步事件循环。libcurl 可以做到这一点,并且有一个名为 pycurl 的 Python 包装器。使用它的“多”接口,您可以进行高性能的客户端活动。我已经完成了超过 1000 次的同时获取,其速度与一次一样快。

但是,API 非常低级且难以使用。这里有一个简化的包装器,您可以将其用作示例。

于 2012-07-24T20:12:48.607 回答
1

在您的用例中,我能想到的最佳方法是使用线程池并维护工作队列。线程池中的线程从工作队列中获取工作,完成工作,然后去获得更多的工作。通过这种方式,您可以精细控制处理 URL 的线程数。

因此,创建一个 WorkQueue,在您的情况下,它基本上是一个包含需要下载的 URL 的列表。

创建一个线程池,它创建您指定的线程数,从 WorkQueue 获取工作并将其分配给一个线程。每次线程完成并返回时,您都会检查工作队列是否有更多工作,并相应地再次将工作分配给该线程。您可能还想放置一个钩子,以便每次将工作添加到工作队列时,如果可用,您的线程会将其分配给空闲线程。

于 2012-07-24T20:09:14.610 回答