如何停止通过runpy.run_module启动的discord.py模块且不关闭PyQt启动器?
解决discord.py从PyQt启动后独立停止、不关闭启动器的方案
核心逻辑是避免机器人的生命周期和启动器主进程/主循环强绑定,通过主动调用官方停止接口、隔离进程的方式实现独立控制。
场景1:GUI模式(cli=False,用qasync运行botLauncher())
你的现有代码已经捕获了协程取消异常,只要调整机器人实例的访问逻辑即可实现优雅停止:
- 首先修改
botLauncher()函数,将hangoutcore模块中初始化后的discord.pyBot实例暴露为可全局访问的变量,不要把启动逻辑完全封死在内部 - 给PyQt界面上的停止按钮绑定异步槽函数,槽函数内主动调用
await bot.close(),该方法是discord.py官方提供的优雅停止接口,会自动清理websocket连接、注销所有事件监听,调用后qasync.run()运行的协程会正常退出,不会影响PyQt主窗口的运行 - 如果hangoutcore模块内用
bot.run()启动,需要给该方法加close_loop=False参数,避免机器人停止时把qasync绑定的Qt事件循环一同关闭
示例调整代码:
# 先从hangoutcore模块暴露Bot实例 from hangoutcore import bot async def botLauncher(): # 原有启动逻辑:加载cog、初始化配置等 await bot.start("你的机器人令牌") # PyQt停止按钮的异步槽函数示例 async def stop_bot(): if bot.is_ready(): await bot.close()
场景2:CLI模式(cli=True,用runpy.run_module启动)
你当前用runpy运行模块是在主进程内执行,hangoutcore模块内bot.run()默认捕获到停止信号后会调用sys.exit(),直接带崩整个启动器进程,改法如下:
- 放弃
runpy方案,改用subprocess.Popen单独开子进程运行hangoutcore模块,停止时只需要终止子进程即可,完全不影响主启动器运行
示例调整代码:
import subprocess import sys # 启动子进程运行机器人 bot_subprocess = subprocess.Popen([sys.executable, "-m", "hangoutcore"]) # 停止机器人时调用该函数即可 def stop_cli_bot(): bot_subprocess.terminate() bot_subprocess.wait()
注意事项
- 不要通过给主进程发SIGINT信号模拟Ctrl+C的方式停止机器人,会直接终止整个启动器进程
- 不要强行取消运行机器人的协程,使用
bot.close()可以保证所有退出事件正常触发,不会出现资源泄漏
内容的提问来源于stack exchange,提问作者Lino
相关产品推荐
相关产品推荐

