Python 学习asyncio:;从来没有人期待过合作”;警告错误

Python 学习asyncio:;从来没有人期待过合作”;警告错误,python,python-asyncio,aiohttp,Python,Python Asyncio,Aiohttp,我正在尝试学习在Python中使用asyncio来优化脚本。 我的示例返回了一个从未等待过的协同程序警告,您能帮助理解并找到解决方法吗 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

我正在尝试学习在Python中使用asyncio来优化脚本。 我的示例返回了一个
从未等待过的协同程序
警告,您能帮助理解并找到解决方法吗

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
函数内部调用完成之前运行。该方法的目的是在同步上下文中运行异步函数。无论如何,以下是您应该如何更改代码:

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()
调用单独创建了一个未来,必须通过显式的
wait
等待(为此,您必须在
async
上下文中)或传递给某个事件循环。独处时,Python会抱怨这一点。在您的原始代码中,您没有这样做。

您通过使用
异步def
使
faire\u toutes\u les\u requetes\u sans\u bloquer
成为一个值得期待的函数,一个协同程序

当您调用一个等待函数时,您将创建一个新的协同程序对象。函数中的代码将不会运行,直到您等待函数或将其作为任务运行:

>>> async def foo():
...     print("Running the foo coroutine")
...
>>> foo()
<coroutine object foo at 0x10b186348>
>>> import asyncio
>>> asyncio.run(foo())
Running the foo coroutine
但是,您也尝试使用
aiophtp.ClientSession()
对象,这是一个异步上下文管理器,您需要将它与
async with
一起使用,而不仅仅是
with
,因此必须在等待的任务旁边运行。如果将
一起使用而不是
一起使用异步,将引发
类型错误(“使用异步与”)
异常

这都意味着您需要移动
循环。运行
调用
faire\u-toutes\u-les\u-requetes\u-sans\u-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")
我使用新的(Python3.7及更高版本)来运行单个主任务。这将为顶级协同路由创建一个专用循环,并运行它直到完成

接下来,需要移动
wait resp.json()
表达式上的结束括号

uid = (await response.json())['uuid']
您希望访问
等待
结果上的
'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")

在我的机器上,同步
在大约4-5秒内请求
代码,而asycio代码在.5秒内完成。

为什么在模块末尾使用
faire_toutes_les_requetes_sans_bloquer()
?该调用创建了可等待的对象(一个协同程序),但您永远不会对其进行
等待
。并且不要忘记导入asyncio
和开始注意:这现在将引发
类型错误(“使用async with”)
,因为
ClientSession()
是一个异步上下文管理器。@MartijnPieters公平,已修复。
exec_time = (datetime.datetime.now() - start).total_seconds()
print(f"Pour faire 10 requêtes, ça prend {exec_time:.3f}s\n")