Discord.py按钮在while循环中失效问题求助
问题分析
你的按钮无响应问题根源在于同步阻塞的while循环卡死了Discord.py的事件循环:
- 原代码中
while (time.time() - start_time) < TIME_TO_START_RACE是同步循环,大部分时间在空转,没有让出事件循环的控制权。 - 之前每次循环都调用
await interaction.edit_original_response,这个await会暂时释放事件循环,让Discord.py能处理按钮交互;而修改后只有新增用户时才调用await,循环持续占用事件循环,导致按钮点击事件无法被处理,直到循环结束后交互超时报错。
解决方案
将同步循环改为异步等待,同时优化参与者列表的去重逻辑,确保事件循环能正常处理交互:
1. 优化View的按钮逻辑(添加去重判断)
class MyView(discord.ui.View): def __init__(self): super().__init__() self.racers = [] @discord.ui.button(label="Join Race!", style=discord.ButtonStyle.success) async def join_race(self, interaction, button): user_id = interaction.user.id if user_id not in self.racers: self.racers.append(user_id) await interaction.response.send_message("You joined the race!", ephemeral=True) else: await interaction.response.send_message("You're already in the race!", ephemeral=True)
2. 修改异步循环逻辑(用asyncio.sleep让出事件循环)
需要先导入asyncio模块:
import asyncio
然后修改StartRace类的方法:
class StartRace: def __init__(self): self.view = MyView() async def start_race_message(self, interaction): # 确保命令发起者加入(避免重复) initiator_id = interaction.user.id if initiator_id not in self.view.racers: self.view.racers.append(initiator_id) start_time = time.time() racers_count = len(self.view.racers) epoch = get_epoch_value() embed = create_race_starting_message_embed(self.view.racers, epoch) # 保存发送的消息对象,方便后续编辑 message = await interaction.response.send_message(embed=embed, view=self.view) while (time.time() - start_time) < TIME_TO_START_RACE: # 异步等待0.5秒,让出事件循环处理交互 await asyncio.sleep(0.5) # 检查是否有新用户加入 if len(self.view.racers) != racers_count: embed = create_race_starting_message_embed(self.view.racers, epoch) await message.edit(embed=embed, view=self.view) racers_count = len(self.view.racers) # 比赛开始:停止View监听,更新消息 self.view.stop() embed = create_race_started_message_embed(self.view.racers) await message.edit(embed=embed, view=self.view)
3. 命令执行逻辑保持不变
@bot.tree.command(name="race", description="Race your friends!") async def race(interaction): start_race = StartRace() await start_race.start_race_message(interaction)
关键改进点
- 异步等待:
asyncio.sleep(0.5)会将控制权交还给事件循环,让Discord.py能处理按钮点击等交互事件,避免阻塞。 - 提前去重:在按钮点击时直接判断用户是否已加入,避免重复添加,无需频繁转换集合,提升效率。
- 停止View监听:循环结束后调用
self.view.stop(),按钮会自动变灰,防止用户后续点击触发无效交互。
内容的提问来源于stack exchange,提问作者why
相关产品推荐
相关产品推荐

