如何在条件不满足时立即终止discord.py的wait_for()协程?
解决discord.py中wait_for无法随全局变量立即终止的问题
方案一:通过asyncio.wait同时监听消息与状态变化
全局变量cond修改后无法立即终止wait_for,是因为wait_for会一直阻塞直到收到符合条件的消息或超时。我们可以用asyncio.wait同时等待两个任务:监听消息的任务,以及持续检查cond状态的任务,只要其中一个完成就终止等待。
修改后的代码:
import asyncio cond = True @bot.command() async def test(ctx): global cond def check(m): return m.author == ctx.author and m.channel == ctx.channel async def monitor_cond(): while cond: await asyncio.sleep(0.5) return "cond_terminated" while cond: done, pending = await asyncio.wait( [bot.wait_for('message', check=check), monitor_cond()], return_when=asyncio.FIRST_COMPLETED ) # 清理未完成的任务 for task in pending: task.cancel() # 判断终止原因 result = next(iter(done)).result() if result == "cond_terminated": break print('Message found!')
方案二:用asyncio.Event替代全局变量(推荐)
使用asyncio.Event比全局变量更适合异步场景,它支持原生的等待操作,无需轮询,可靠性更高。
代码示例:
import asyncio stop_event = asyncio.Event() @bot.command() async def test(ctx): def check(m): return m.author == ctx.author and m.channel == ctx.channel stop_event.clear() # 重置事件,确保每次命令执行初始状态正确 while not stop_event.is_set(): done, pending = await asyncio.wait( [bot.wait_for('message', check=check), stop_event.wait()], return_when=asyncio.FIRST_COMPLETED, timeout=7200 ) # 取消未完成任务 for task in pending: task.cancel() for task in done: try: res = task.result() if res is None: # stop_event.wait()触发时返回None break print('Message found!') except asyncio.TimeoutError: print('No message was found.') # 用于终止test命令的示例命令 @bot.command() async def stop_test(ctx): stop_event.set() await ctx.send("Test命令已终止")
核心原理
两种方案都是利用asyncio.wait的FIRST_COMPLETED模式,让程序同时监听多个异步任务,只要其中一个任务完成(无论是收到消息、状态变化还是超时),就立即处理并终止其他任务,从而实现wait_for的即时终止。
内容的提问来源于stack exchange,提问作者Angel
相关产品推荐
相关产品推荐

