Python 3.10 asyncio.gather() 显示 DeprecationWarning: 没有当前事件循环

sve*_*cax 5 python python-asyncio python-3.10

我有一个 Django 应用程序,在其视图之一中,我使用 asyncio 来向外部组件发出一些并发请求。

这个想法是这样的:

import asyncio


async def do_request(project):
    result = ...

    return result

def aggregate_results(projects: list):
    loop = asyncio.new_event_loop()

    asyncio.set_event_loop(loop)

    results = loop.run_until_complete(
        asyncio.gather(*(do_request(project) for project in projects))
    )

    loop.close()

    return zip(projects, results)
Run Code Online (Sandbox Code Playgroud)

好吧,当我运行测试时,我得到了DeprecationWarning: There is no current event loop这一行:

        asyncio.gather(*(do_request(project) for project in projects))
Run Code Online (Sandbox Code Playgroud)

我应该如何解释此警告以及我需要进行哪些更改才能消除它?谢谢!

dir*_*irn 7

根据文档,发生这种情况是因为调用时gather没有事件循环运行。

自版本 3.10 起已弃用:如果未提供位置参数或并非所有位置参数都是类似 Future 的对象并且没有正在运行的事件循环,则会发出弃用警告。

您可能已经注意到,您的代码可以正常工作。它将继续工作,只要您使用 3.10,您就可以忽略弃用警告。不过,在将来的某个时候,这可能会更改为运行时错误。

如果您耐心等待一下,运行事件循环的推荐方法是使用run,而不是loop.run_until_complete

def aggregate_results(projects: list):
    results = asyncio.run(asyncio.gather(*(do_request(project) for project in projects)))
    return zip(projects, results)
Run Code Online (Sandbox Code Playgroud)

然而,这实际上行不通。相反,你会得到一个例外

ValueError: a coroutine was expected, got <_GatheringFuture pending>
Run Code Online (Sandbox Code Playgroud)

解决方法是等待gather另一个协程。

async def get_project_results(projects: list):
    results = await asyncio.gather(*(do_request(project) for project in projects))
    return results

def aggregate_results(projects: list):
    results = asyncio.run(get_project_results(projects))
    return zip(projects, results)
Run Code Online (Sandbox Code Playgroud)

get_project_results(您也可以与您的版本一起使用aggregate_results。)