Python 如何设置后台计时器,并在函数完成时停止它,同时仍在等待反应

Python 如何设置后台计时器,并在函数完成时停止它,同时仍在等待反应,python,discord.py,python-asyncio,Python,Discord.py,Python Asyncio,所以我用discord.py制作了一些小游戏,我得到的是: asyncio.create_任务(self.stream_message_timer(ctx,correct,total),name=f“stream message timer{ctx.author.id}”) 当坏计数>0时: 完成,挂起=等待异步IO.wait([ self.client.wait_for('reaction_add',check=lambda reaction,user:str(reaction.emoji)在

所以我用discord.py制作了一些小游戏,我得到的是:

asyncio.create_任务(self.stream_message_timer(ctx,correct,total),name=f“stream message timer{ctx.author.id}”)
当坏计数>0时:
完成,挂起=等待异步IO.wait([
self.client.wait_for('reaction_add',check=lambda reaction,user:str(reaction.emoji)在number_emojis和reaction.message.id==discord_message.id和user==ctx.author中),
self.client.wait_for('message',check=lambda m:m.author==self.client.user和m.content==f“Times up!\n{correct}/{total}任务成功。”)
],在=asyncio.FIRST_完成时返回_)
尝试:
result=done.pop().result()
例外情况除外,如e:
提高e
为便于将来完成:
future.exception()
未来待定:
future.cancel()
如果类型(结果)=不一致。消息:
返回错误
其他:
反应=结果
#处理反应,编辑消息
等待ctx.send(f“您删除了所有错误消息!\n{correct+1}/{total}任务成功。”)
对于异步IO中的任务。所有_任务():
如果task.get_name()==f“流消息计时器{ctx.author.id}”:
task.cancel()
打破
返回真值
异步def流消息计时器(自身、ctx、正确、总计):
等待异步睡眠(5)
等待ctx.send(f“Times up!\n{correct}/{total}tasks successful.”#链接到delete_chat的消息,如果更改,请在此处更改
返回错误
基本上,我正在尝试制作某种5秒的背景计时器,同时等待反应。
不,我不是在寻找
timeout=5


我这里的代码是有效的,但它非常粗糙。我不是在等待用户的反应,就是在等待机器人发送消息“Times up”

有没有更干净的方法?我想让计时器在while循环之前启动,并强制停止循环中的任何内容,并在计时器完成时使函数返回False

此外,如果函数确实停止,我仍然需要某种方法来取消计时器,并且只取消该计时器。

我已经使用这个方法很长时间了,它使得我的代码非常无序。谢谢

下面是一些独立于discord.py的示例:

导入异步IO
随机输入
异步def main():
asyncio.create_任务(timer(),name=“some task name”)
#模拟等待用户输入
等待asyncio.sleep(随机、一致(2,5))
返回真值
异步定义计时器():
等待异步睡眠(5)
#以某种方式使这个return语句停止main()函数
返回错误
asyncio.run(main())
等待(return\u when=FIRST\u COMPLETED)
是正确的方法,但您可以使用
create\u task的返回值简化调用(以及随后的取消):

async def main():
    timer_task = asyncio.create_task(timer())
    user_input_task = asyncio.create_task(asyncio.sleep(random.uniform(2, 5)))
    await asyncio.wait([timer_task, user_input_task], return_when=asyncio.FIRST_COMPLETED)

    if not timer_task.done():
        timer_task.cancel()

    if user_input_task.done():
        # we've finished the user input
        result = await user_input_task
        ...
    else:
        # we've timed out
        await timer_task   # to propagate exceptions, if any
        ...

如果此模式在代码库中大量重复,您可以轻松地将其抽象为实用程序函数。

您是否可以编辑答案以创建一个自包含的可运行示例,即不依赖于项目中定义的discord和类的示例?这将使代码更容易理解和改进。@user4815162342我现在已经编辑了它,如果这有助于理解的话,但是这个示例似乎无法运行。一个可运行的示例可以对您的代码进行实验,然后为了清晰起见对其进行改进。我想不出另一种情况,即我正在等待用户的输入。您可以使用asyncio.sleep或类似方法模拟等待用户的输入。有关提供可复制示例的详细信息,请参见例如。