我可以一次对多个函数使用await吗?



我正在学习python中并发的魔力,我有一个脚本,我一直在使用await(通过fastapi的框架)。

我需要从我的数据库中获得多个数据,并做一些像:

DBresults1 = await db_conn.fetch_rows(query_statement1)
DBresults2 = await db_conn.fetch_rows(query_statement2)
DBresults3 = await db_conn.fetch_rows(query_statement3)
#then on to processing...

问题是我的等待导致我的代码顺序运行,这变得很慢。

是否有一种方法可以让我的3个查询(或任何函数调用)在没有等待的情况下运行,但等待直到整个组完成,所以它可以并发执行?

可以使用gather非顺序地等待多个任务。您提到了FastAPI,这个例子可能会有所帮助。它在大约3秒内完成一个3秒的任务和一个2秒的任务。虽然第一个任务需要更长的时间,但是gather将按照您列出结果的顺序给出结果,而不是按照它们完成的顺序。

要使其工作,长时间运行的部分需要是实际的可等待IO(这里用asyncio.sleep模拟),而不是CPU限制的工作。

如果你在终端上运行这个,然后从Postman调用GET localhost:8080(或者任何你方便的),你会看到日志中发生了什么。

import logging
import asyncio
import time
from fastapi import FastAPI
logging.basicConfig(level=logging.INFO, format="%(levelname)-9s %(asctime)s - %(name)s - %(message)s")
LOGGER = logging.getLogger(__name__)
app = FastAPI()
async def takes_three():
LOGGER.info("will sleep for 3s...")
await asyncio.sleep(3)
LOGGER.info("takes_three awake!")
return "takes_three done"
async def takes_two():
LOGGER.info("will sleep for 2s...")
await asyncio.sleep(2)
LOGGER.info("takes_two awake!")
return "takes_two done"

@app.get("/")
async def root():
start_time = time.time()
LOGGER.info("starting...")
results = await asyncio.gather(*[takes_three(), takes_two()])
duration = time.time() - start_time
LOGGER.info(f"results: {results} after {duration:.2f}")
return f"finished after {duration:.2f}s!"

if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8080)

您可以像下面的示例一样使用asyncio.wait

async def get_suggest(entity, ids, company_id):
...
return ...

jobs = []
for entity, ids, in dict(data.filters).items():
jobs.append(get_suggest(entity, ids, company_id))
result = {}
done, _ = await asyncio.wait(jobs)
for job in done:
values, entity = job.result()
result[entity] = values

最新更新