学习异步:"coroutine was never awaited" 警告错误
Learning asyncio: "coroutine was never awaited" warning error
我正在尝试学习在 Python 中使用 asyncio 来优化脚本。
我的例子 returns 一个 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
不要在 async
函数中使用 loop.run_until_complete
调用。该方法的目的是 运行 同步上下文中的异步函数。无论如何,您应该如何更改代码:
async def faire_toutes_les_requetes_sans_bloquer():
async with aiohttp.ClientSession() as session:
futures = [requete_sans_bloquer(x, session) for x in range(10)]
await asyncio.gather(*futures)
print("Fin de la boucle !")
loop = asyncio.get_event_loop()
loop.run_until_complete(faire_toutes_les_requetes_sans_bloquer())
请注意,单独 faire_toutes_les_requetes_sans_bloquer()
调用会创建一个必须通过显式 await
等待的未来(因为你必须在 async
上下文中)或传递给某个事件环形。当一个人离开时 Python 会抱怨。在您的原始代码中,您执行了 none 个操作。
您使用 async def
.
创建了 faire_toutes_les_requetes_sans_bloquer
一个 awaitable 函数,一个协程
当你调用一个等待函数时,你创建了一个新的协程对象。函数内的代码不会 运行 直到你 await 函数或 运行 它作为任务:
>>> async def foo():
... print("Running the foo coroutine")
...
>>> foo()
<coroutine object foo at 0x10b186348>
>>> import asyncio
>>> asyncio.run(foo())
Running the foo coroutine
您想保持该函数同步,因为直到进入该函数才开始循环:
def faire_toutes_les_requetes_sans_bloquer():
loop = asyncio.get_event_loop()
# ...
loop.close()
print("Fin de la boucle !")
但是,您还尝试使用 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()
上呼叫并等待:
async def faire_toutes_les_requetes_sans_bloquer():
async with aiohttp.ClientSession() as session:
futures = [requete_sans_bloquer(x, session) for x in range(10)]
await asyncio.gather(*futures)
print("Fin de la boucle !")
print("Non bloquant : ")
start = datetime.datetime.now()
loop.run(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")
我使用新的 asyncio.run()
function(Python 3.7 及更高版本)来 运行 单个主要任务。这会为该顶级协程创建一个专用循环并运行s它直到完成。
接下来,您需要移动 await resp.json()
表达式的右 )
括号:
uid = (await response.json())['uuid']
您想访问 await
结果上的 'uuid'
键,而不是 response.json()
产生的协程。
通过这些更改,您的代码可以正常工作,但 asyncio 版本会在亚秒级时间内完成;你可能想要打印微秒:
exec_time = (datetime.datetime.now() - start).total_seconds()
print(f"Pour faire 10 requêtes, ça prend {exec_time:.3f}s\n")
在我的机器上,同步 requests
代码大约需要 4-5 秒,asycio 代码在 0.5 秒内完成。
我正在尝试学习在 Python 中使用 asyncio 来优化脚本。
我的例子 returns 一个 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
不要在 async
函数中使用 loop.run_until_complete
调用。该方法的目的是 运行 同步上下文中的异步函数。无论如何,您应该如何更改代码:
async def faire_toutes_les_requetes_sans_bloquer():
async with aiohttp.ClientSession() as session:
futures = [requete_sans_bloquer(x, session) for x in range(10)]
await asyncio.gather(*futures)
print("Fin de la boucle !")
loop = asyncio.get_event_loop()
loop.run_until_complete(faire_toutes_les_requetes_sans_bloquer())
请注意,单独 faire_toutes_les_requetes_sans_bloquer()
调用会创建一个必须通过显式 await
等待的未来(因为你必须在 async
上下文中)或传递给某个事件环形。当一个人离开时 Python 会抱怨。在您的原始代码中,您执行了 none 个操作。
您使用 async def
.
faire_toutes_les_requetes_sans_bloquer
一个 awaitable 函数,一个协程
当你调用一个等待函数时,你创建了一个新的协程对象。函数内的代码不会 运行 直到你 await 函数或 运行 它作为任务:
>>> async def foo():
... print("Running the foo coroutine")
...
>>> foo()
<coroutine object foo at 0x10b186348>
>>> import asyncio
>>> asyncio.run(foo())
Running the foo coroutine
您想保持该函数同步,因为直到进入该函数才开始循环:
def faire_toutes_les_requetes_sans_bloquer():
loop = asyncio.get_event_loop()
# ...
loop.close()
print("Fin de la boucle !")
但是,您还尝试使用 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()
上呼叫并等待:
async def faire_toutes_les_requetes_sans_bloquer():
async with aiohttp.ClientSession() as session:
futures = [requete_sans_bloquer(x, session) for x in range(10)]
await asyncio.gather(*futures)
print("Fin de la boucle !")
print("Non bloquant : ")
start = datetime.datetime.now()
loop.run(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")
我使用新的 asyncio.run()
function(Python 3.7 及更高版本)来 运行 单个主要任务。这会为该顶级协程创建一个专用循环并运行s它直到完成。
接下来,您需要移动 await resp.json()
表达式的右 )
括号:
uid = (await response.json())['uuid']
您想访问 await
结果上的 'uuid'
键,而不是 response.json()
产生的协程。
通过这些更改,您的代码可以正常工作,但 asyncio 版本会在亚秒级时间内完成;你可能想要打印微秒:
exec_time = (datetime.datetime.now() - start).total_seconds()
print(f"Pour faire 10 requêtes, ça prend {exec_time:.3f}s\n")
在我的机器上,同步 requests
代码大约需要 4-5 秒,asycio 代码在 0.5 秒内完成。