Python非阻塞式定时器实现问询:避免阻塞其他脚本运行
解决Discord Slash命令定时器阻塞问题
原代码问题分析
你提供的定时器代码使用了同步的time.sleep(1),在异步函数中调用该方法会直接阻塞整个事件循环,导致机器人无法响应其他命令或事件,直到定时器结束。同时代码存在大量重复逻辑,不利于后续维护。
解决方案
通过异步睡眠替代同步睡眠,并重构代码减少冗余,实现非阻塞的定时器功能:
改进后代码
import asyncio import lightbulb # 通用定时器逻辑 async def run_timer(ctx, total_minutes: int, notify_interval_sec: int): await ctx.respond(f"Timer for {total_minutes} minute⌛ start!") await ctx.respond("https://upload.wikimedia.org/wikipedia/commons/7/7a/Alarm_Clock_GIF_Animation_High_Res.gif") total_seconds = total_minutes * 60 for second in range(total_seconds): await asyncio.sleep(1) # 异步睡眠,不阻塞事件循环 # 到达通知间隔且非初始时刻时发送提醒 if second % notify_interval_sec == 0 and second != 0: elapsed_minutes = second // 60 await ctx.respond(f"{elapsed_minutes} minute⌛ has passed!") await ctx.respond("Timer ended!") @my_group.child @lightbulb.command('five', '5 minute countdown') @lightbulb.implements(lightbulb.SlashSubCommand) async def five_minute_timer(ctx): await run_timer(ctx, 5, 60) # 每分钟通知一次 @my_group.child @lightbulb.command('ten', '10 minute countdown') @lightbulb.implements(lightbulb.SlashSubCommand) async def ten_minute_timer(ctx): await run_timer(ctx, 10, 60) # 每分钟通知一次 @my_group.child @lightbulb.command('thirty', '30 minute countdown') @lightbulb.implements(lightbulb.SlashSubCommand) async def thirty_minute_timer(ctx): await run_timer(ctx, 30, 300) # 每5分钟通知一次
关键改进点
- 替换同步睡眠:用
asyncio.sleep(1)替代time.sleep(1),异步睡眠会将控制权交还给事件循环,让机器人可以同时处理其他任务,不会造成阻塞。 - 代码复用:抽离通用的定时器逻辑到
run_timer函数,三个子命令只需传入参数即可,大幅减少重复代码。 - 保留原有通知逻辑:5/10分钟定时器每分钟通知一次,30分钟定时器每5分钟通知一次,与原需求保持一致。
内容的提问来源于stack exchange,提问作者Kitty Summoner
相关产品推荐
相关产品推荐

