我正在尝试解决一个问题,我有很多(大约一万个)网址,需要从所有网址下载内容。我一直这样做是为了“链接中的链接:”循环到现在为止,但现在花费的时间太长了。我认为是时候实现多线程或多处理方法了。我的问题是,最好的方法是什么?
我知道全局解释器锁,但由于我的问题是网络限制的,而不是CPU限制的,我认为这不会是一个问题。我需要将数据从每个线程/进程传回主线程/进程。我不需要帮助实现任何方法(Terminate multiple threads when any thread completes a task涵盖那些),我需要建议采取哪种方法。我目前的做法:
data_list = get_data(...)
output = []
for datum in data:
output.append(get_URL_data(datum))
return output
没有其他共享状态。
我认为最好的方法是拥有一个包含所有数据的队列,并从输入队列中弹出几个工作线程,获取URL数据,然后推送到输出队列。
我是对的吗?有什么我想念的吗?这是我第一次用任何语言实现多线程代码,我知道这通常是一个难题。
答案 0 :(得分:5)
对于您的具体任务,我建议multiprocessing worker pool。您只需定义一个池并告诉它您要使用多少个进程(默认情况下每个处理器核心一个)以及您希望在每个工作单元上运行的函数。然后,您准备好每个工作单元(在您的情况下,这将是一个URL列表)并将其提供给工作池。
您的输出将是原始数组中每个工作项的工作函数返回值的列表。所有酷炫的多处理优点都将在后台进行。当然还有其他工作方式,但这是我最喜欢的方式。
快乐的多处理!
答案 1 :(得分:2)
执行此类IO绑定任务的最快速,最有效的方法是异步事件循环。 libcurl可以做到这一点,并且有一个名为pycurl的Python包装器。使用它的“多”界面,您可以执行高性能的客户端活动。我已经完成了1000多次同步提取。
然而,API非常低级且难以使用。有一个简化的包装器here,您可以将其用作示例。
答案 2 :(得分:1)
我在您的用例中可以想到的最佳方法是使用线程池并维护工作队列。线程池中的线程从工作队列中获得工作,完成工作然后再做一些工作。这样,您就可以精确控制处理URL的线程数。
因此,创建一个WorkQueue,在您的情况下基本上是一个包含需要下载的URL的列表。
创建一个线程池,它创建您指定的线程数,从WorkQueue获取工作并将其分配给线程。每次线程完成并返回时,检查工作队列是否有更多工作,并相应地再次为该线程分配工作。您可能还想放置一个钩子,以便每次将工作添加到工作队列时,您的线程会将其分配给一个空闲线程(如果可用)。