并行这个webcrawling循环的最佳方法是什么?

2024-09-29 06:22:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在做一个网络爬虫,我有一些“睡眠”功能,使爬网相当长。 现在我在做:

for speciality in range(1,25):
    for year in range(1997, 2017):
        for quarter in [1,2]:
            deal_with (driver, year, quarter, speciality, ok)

deal_with函数正在打开几个网页,等待几秒钟完成html下载,然后继续。执行时间非常长:有25*10*2=500个循环,每个循环不少于一分钟。你知道吗

我想用我的4个物理内核(8个线程)来享受并行性。 我读到了龙卷风,多重处理,作业库。。。我真的不能决定一个简单的解决方案来适应我的代码。你知道吗

任何见解欢迎:-)


Tags: 函数in功能网络网页fordriverwith
2条回答
<>太长了,读不下去了,你就不能帮助你。

归根结底,只有两种基本方法可以扩展这样的任务:

多重处理

启动许多Python进程,并将任务分发给每个进程。这是你认为对你有帮助的方法。你知道吗

尽管您可以使用任何适当的包装器,但仍可以使用一些示例代码来说明其工作原理:

import multiprocessing

# general rule of thumb: launch twice as many processes as cores

process_pool = multiprocessing.Pool(8) # launches 8 processes

# generate a list of all inputs you wish to feed to this pool

inputs = []

for speciality in range(1,25):
    for year in range(1997, 2017):
        for quarter in [1,2]:
            inputs.append((driver, year, quarter, speciality, ok))

# feed your list of inputs to your process_pool and print it when done
print(process_pool.map(deal_with, inputs))

如果这是你想要的,你现在可以停止阅读了。你知道吗

异步执行

在这里,您只满足于一个线程或进程,但您不希望它空闲地等待网络读取或磁盘查找之类的内容返回—您希望它在等待的同时继续做其他更重要的事情。你知道吗

真正的本机异步I/O支持在Python3中提供,在Twisted networking库之外的Python2.7中不存在。你知道吗

import concurrent.futures

# generate a list of all inputs you wish to feed to this pool

inputs = []

for speciality in range(1,25):
    for year in range(1997, 2017):
        for quarter in [1,2]:
            inputs.append((driver, year, quarter, speciality, ok))

# produce a pool of processes, and make sure they don't block each other
# - get back an object representing something yet to be resolved, that will
# only be updated when data comes in.

with concurrent.futures.ProcessPoolExecutor() as executor:
    outputs = [executor.submit(input_tuple) for input_tuple in inputs]

    # wait for all of them to finish - not ideal, since it defeats the purpose
    # in production, but sufficient for an example

    for future_object in concurrent.futures.as_completed(outputs):
         # do something with future_object.result()

那有什么区别?你知道吗

我在这里的主要观点是强调,从一系列技术中进行选择并不像找出真正的瓶颈在哪里那么难。你知道吗

在上面的例子中,没有任何区别。两者都遵循一个简单的模式:

  1. 有很多工人
  2. 允许这些工作人员立即从任务队列中选择某些内容
  3. 当一个人有空的时候,让他们马上去做下一个。你知道吗

因此,如果你一字不差地遵循这些示例,即使它们使用完全不同的技术,并且声称使用完全不同的技术,你也不会获得概念上的差异。你知道吗

如果按照这种模式编写,您选择的任何技术都将是徒劳的—即使您会得到一些加速,但如果您期望获得巨大的性能提升,您将非常失望。你知道吗

为什么这种模式不好?因为这不能解决你的问题。你知道吗

你的问题很简单:你必须等待。当您的进程正在等待某些东西返回时,它不能做其他任何事情!它不能为你调用更多的页面。它无法处理传入的任务。它所能做的就是等待。你知道吗

让更多的进程最终等待并不是真正的解决方案。一支必须向滑铁卢进军的军队,如果你把它分成几个团,速度不会更快——每个团最终都要睡觉,尽管他们可能在不同的时间、不同的长度睡觉,而结果是,他们几乎都会在同一时间到达。你知道吗

你需要的是一支永不停息的军队。你知道吗

那你该怎么办?你知道吗

所有I/O任务抽象为非阻塞。这是你真正的瓶颈。如果你在等待一个网络响应,不要让糟糕的过程就这样坐以待毙——给它做点什么。你知道吗

您的任务变得有些困难,因为默认情况下,从套接字读取是阻塞的。操作系统就是这样。谢天谢地,您不需要用python3来解决这个问题(尽管这始终是首选的解决方案)asyncore库(though Twisted is comparably superior in every way)已经存在于python2.7中,可以在后台进行真正的网络读写。你知道吗

只有一种情况需要在Python中使用真正的多处理,那就是如果您正在进行CPU受限或CPU密集型的工作。从你的描述来看,好像不是这样的。你知道吗

简而言之,您应该编辑deal_with函数以避免初期的等待。如果需要的话,可以使用Twisted或asyncore中合适的抽象在后台等待。但不要让它完全消耗你的过程。你知道吗

如果您使用的是python3,我会查看asycio module。我相信你可以用@asyncio.coroutine来装饰deal_with。您可能需要调整deal_with所做的工作,才能正确地处理事件循环。你知道吗

相关问题 更多 >