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

时间:2018-02-21 02:14:55

标签: python asynchronous networking parallel-processing python-asyncio

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

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

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

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

1 个答案:

答案 0 :(得分:4)

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))