第一次完成后取消两个异步协程

thr*_*409 2 python python-asyncio discord.py

我正在用 Python 制作一个 Discord 机器人。我想要做的就是等待两个协程,一旦第一个协程完成,就运行其余的代码,但取消剩余的协程(与这里不同,我只有一个协程并希望在特定时间后取消它) .)

这是最小的可重现示例:

import asyncio
import discord

client = discord.Client()

async def testfunc():
    await asyncio.sleep(10)
    print("10 seconds.")

async def testfunc2():
    await asyncio.sleep(15)
    print("15 seconds.")

@client.event
async def on_ready():
    print("Connected!")
    await asyncio.wait([testfunc(),testfunc2()],return_when=asyncio.FIRST_COMPLETED)

client.run('MY BOT TOKEN')
Run Code Online (Sandbox Code Playgroud)

我打算在这个最小的示例中打印“10 秒”。10 秒后,不再打印任何其他内容。然而,实际发生的情况是它还打印了“15 秒”。15 秒后,我想取消该协程,这样就不会发生这种情况。

在这种情况下,我似乎无法使用 asyncio.wait_for,因为有两个协程而不是一个,两个协程必须同时运行,直到一个协程完成。由于 asyncio.wait 在协程完成后不会取消协程,有什么方法可以取消它们吗?

Pat*_*ugh 5

如果将协程包装在任务中,则可以取消未完成的任务

@client.event
async def on_ready():
    print("Connected!")
    tasks = [asyncio.create_task(testfunc()), asyncio.create_task(testfunc2())]
    await asyncio.wait(tasks,return_when=asyncio.FIRST_COMPLETED)
    for task in tasks:
        if not task.done():
            task.cancel()
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`asyncio.wait` 已经在单独的集合中返回已完成和待处理的任务,因此更容易:`_,pending = wait asyncio.wait(...); 对于待处理的任务:task.cancel()` (2认同)