我正在尝试学习在 Python 中使用 asyncio 来优化脚本。我的例子返回一个 coroutine was never awaited
警告,你能帮助理解并找到解决方法吗?
import time
import datetime
import random
import asyncio
import aiohttp
import requests
def requete_bloquante(num):
print(f'Get {num}')
uid = requests.get("https://httpbin.org/uuid").json()['uuid']
print(f"Res {num}: {uid}")
def faire_toutes_les_requetes():
for x in range(10):
requete_bloquante(x)
print("Bloquant : ")
start = datetime.datetime.now()
faire_toutes_les_requetes()
exec_time = (datetime.datetime.now() - start).seconds
print(f"Pour faire 10 requêtes, ça prend {exec_time}s\n")
async def requete_sans_bloquer(num, session):
print(f'Get {num}')
async with session.get("https://httpbin.org/uuid") as response:
uid = (await response.json()['uuid'])
print(f"Res {num}: {uid}")
async def faire_toutes_les_requetes_sans_bloquer():
loop = asyncio.get_event_loop()
with aiohttp.ClientSession() as session:
futures = [requete_sans_bloquer(x, session) for x in range(10)]
loop.run_until_complete(asyncio.gather(*futures))
loop.close()
print("Fin de la boucle !")
print("Non bloquant : ")
start = datetime.datetime.now()
faire_toutes_les_requetes_sans_bloquer()
exec_time = (datetime.datetime.now() - start).seconds
print(f"Pour faire 10 requêtes, ça prend {exec_time}s\n")
代码的第一部分 经典 部分运行正确,但后半部分只产生:
synchronicite.py:43: RuntimeWarning: coroutine 'faire_toutes_les_requetes_sans_bloquer' was never awaited
原文由 Anthony Hervy 发布,翻译遵循 CC BY-SA 4.0 许可协议
您使用
async def
制作了faire_toutes_les_requetes_sans_bloquer
一个 等待 函数,一个协程。当你调用一个等待函数时,你创建了一个新的协程对象。函数内的代码不会运行,直到您 等待 函数或将其作为任务运行:
你想保持那个函数 _同步_,因为你直到在那个函数内部才开始循环:
但是,您还尝试使用
aiophttp.ClientSession()
对象,这是一个 _异步上下文管理器_,您应该将它与async with
一起使用,而不仅仅是with
因此必须在等待任务中运行。如果您使用with
而不是async with
--- 将引发TypeError("Use async with instead")
异常。这一切都意味着您需要将
loop.run_until_complete()
调用 移出 您的faire_toutes_les_requetes_sans_bloquer()
函数,这样您就可以将其作为要运行的主要任务;您可以直接在asycio.gather()
上致电并等待:我使用了新的
asyncio.run()
函数(Python 3.7 及更高版本)来运行单个主任务。这为该顶级协程创建了一个专用循环并运行它直到完成。接下来,您需要移动
)
await resp.json()
:您想要访问
'uuid'
await
,而不是response.json()
产生的协程。通过这些更改,您的代码可以工作,但 asyncio 版本会在亚秒级时间内完成;你可能想要打印微秒:
在我的机器上,同步
requests
代码大约需要 4-5 秒,asycio 代码在 0.5 秒内完成。