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

如何修复Discord.py中的RuntimeError: set_wakeup_fd仅在主线程生效

Discord.py机器人启动错误修复方案

问题根源

你遇到的RuntimeError: set_wakeup_fd only works in main thread错误确实是因为用threading.Thread启动bot.run()导致的:

  • bot.run()是discord.py的阻塞式启动方法,内部会注册系统信号处理(比如Ctrl+C终止),而信号处理必须在主线程执行,放到子线程会触发该错误。
  • 换成bot.start()后出现“从未被await”的错误,是因为bot.start()是异步方法,必须用await关键字调用,不能直接作为线程目标执行。

修复方案(最优)

直接在主线程运行bot.run(),并将循环任务myLoop的启动时机放到bot的on_ready事件中(确保bot完成登录、获取服务器资源后再执行任务),修改后的核心代码如下:

def discordbot(self):
    self.bot = commands.Bot(
        command_prefix=".",
        help_command=None,
        intents=discord.Intents().all(),
        activity=discord.Game(name="Darkys Backup")
    )

    @tasks.loop(seconds=3)
    async def myLoop():
        for i in ListToSend:
            membercount = str(len(Memberdb.GetMembers()))
            # 用get_channel替代get_all_channels,效率更高
            channel = self.bot.get_channel(int(self.log_channel))
            if not channel:
                continue  # 避免找不到频道导致报错
            
            embed = discord.Embed(
                title='',
                description="""**✅ | Member verified**
≡ | User: <@{0}>
≡ | Ip: `{1}`
≡ | Member in db: `{2}`""".format(i['userid'], i['ip'], membercount),
                color=5763719
            )
            await channel.send(embed=embed)

            guild = self.bot.get_guild(int(self.ServerId))
            if not guild:
                continue
            role = discord.utils.get(guild.roles, name=self.role_name)
            if not role:
                continue
            
            try:
                # 用服务器内的get_member替代全局get_all_members,效率更高
                member = guild.get_member(int(i['userid']))
                if member:
                    await member.add_roles(role)
            except Exception as e:
                print(f"添加角色失败: {e}")  # 打印异常便于排查,不要吞掉所有错误
        ListToSend.clear()

    # 等Bot完全登录就绪后启动循环任务
    @self.bot.event
    async def on_ready():
        print(f"Bot已登录: {self.bot.user.name}")
        myLoop.start()

    # 直接在主线程运行Bot,不要用子线程
    self.bot.run(self.BotToken)

额外优化点

  • 替换了低效的资源查找方法,提升代码性能
  • 添加空值判断,避免因资源未找到引发的异常
  • 移除空except块,改为捕获具体异常并打印,便于调试

特殊场景处理(如果需要和非异步代码共存)

如果你的程序有其他非异步主线程逻辑,需要将discord.py的事件循环集成到主线程中,可通过asyncio.run_coroutine_threadsafe在子线程事件循环中执行异步任务,但优先推荐上述方案,因为discord.py本身是异步框架,统一在一个事件循环中处理逻辑更稳定。

内容的提问来源于stack exchange,提问作者sub joel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 15:30:59