如何在 Python 中不浪费时间等待许多网络绑定任务?

How to not waste time waiting for many network-bound tasks in Python?

在我的 Python 控制台应用程序中,我有一个简单的 for 循环,如下所示:

for package in page.packages:
    package.load()
    # do stuff with package

每次调用时,package.load() 都会发出一系列 HTTP 请求。由于 page.packages 通常包含数千个包,因此 load() 调用正在成为我的应用程序的重大瓶颈。

为了加快处理速度,我考虑过使用 multiprocessing 模块进行并行化,但仍然会浪费大量资源,因为线程是网络绑定的,而不是 CPU -bound:不是让 1 个线程无所事事地等待,而是有 4 个。是否可以使用异步而不是以某种方式只使用 one/a 几个线程,但要确保它们永远不会等待网络?

asyncio 非常适合这个,但是您需要使用 aiohttp 之类的东西将您的 HTTP 加载代码 Package.load 转换为异步。例如:

async def load(self):
    with self._session.get(self.uri, params) as resp:
        data = resp.read()  # etc

您之前的顺序循环可以表示为:

async def load_all_serial(page):
    for package in page.packages:
        await package.load()

但现在您还可以选择并行开始下载:

async def load_all_parallel(page):
    # just create tasks, do not await them yet
    tasks = [package.load() for package in page.packages]
    # now let them run, and wait until all have been completed
    await asyncio.gather(*tasks)

从同步代码调用这些异步函数中的任何一个都非常简单:

loop = asyncio.get_event_loop()
loop.run_until_complete(load_all_parallel(page))