You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 22:23:11