如何修复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
相关产品推荐
相关产品推荐

