Python Discord Bot配置max_workers=4后运行失败的问题排查与修复
错误原因分析
1. 协程未等待警告(RuntimeWarning)
discord.py v2.x版本起,bot.load_extension()变为异步函数,必须使用await关键字调用。你的代码在事件循环外直接同步调用该函数,导致协程从未被执行,抛出警告。虽然控制台打印了"cog loaded",但实际cogs并未真正加载。
2. ThreadPoolExecutor初始化错误(TypeError)
从错误栈可以看出,asyncio在执行DNS解析时尝试创建默认ThreadPoolExecutor,但报错缺少max_workers参数。这大概率是因为你的Python环境中安装了第三方futures库(为Python 2提供的兼容库),它覆盖了标准库的concurrent.futures模块。旧版本的第三方futures库要求ThreadPoolExecutor必须传入max_workers参数,而标准库的ThreadPoolExecutor在Python 3.8+中该参数是可选的。
另外,你代码中定义的executor = concurrent.futures.ThreadPoolExecutor(max_workers=4)并未被实际使用,无法替代asyncio的默认执行器,因此无法解决这个问题。
修复方案
步骤1:修复cogs加载问题
将cogs加载逻辑移至异步的setup_hook函数中(discord.py推荐的方式),确保使用await调用load_extension:
# 替换原来的cogs加载for循环 @bot.setup_hook async def setup_hooks(): cogs = ["admin", "member"] for cog in cogs: try: await bot.load_extension(f'cogs.{cog.lower()}') print(f'{cog} cog loaded.') except Exception as e: print(f'Failed to load {cog} cog: {e}')
步骤2:解决ThreadPoolExecutor参数问题
方案A:移除第三方futures库(推荐)
如果你的环境不需要Python 2兼容,直接卸载第三方futures库:
pip uninstall futures
标准库的concurrent.futures完全满足需求,且不会出现参数必填问题。
方案B:显式设置asyncio默认执行器
如果必须保留futures库,在代码中显式将你创建的executor设置为asyncio事件循环的默认执行器:
# 在bot定义后添加 executor = concurrent.futures.ThreadPoolExecutor(max_workers=4) loop = asyncio.get_event_loop() loop.set_default_executor(executor)
完整修复后的main.py代码
#discord imports import discord from discord.ext import commands #module imports import asyncio import concurrent.futures from dotenv import load_dotenv import os #token load_dotenv() token = os.getenv("DISCORD_TOKEN") # 从.env文件读取token,更安全 #intents and bot intents = discord.Intents.all() bot = commands.Bot(command_prefix="?", intents=intents) # 设置默认执行器(仅当保留futures库时添加) executor = concurrent.futures.ThreadPoolExecutor(max_workers=4) loop = asyncio.get_event_loop() loop.set_default_executor(executor) # 异步加载cogs @bot.setup_hook async def setup_hooks(): cogs = ["admin", "member"] for cog in cogs: try: await bot.load_extension(f'cogs.{cog.lower()}') print(f'{cog} cog loaded.') except Exception as e: print(f'Failed to load {cog} cog: {e}') #login event @bot.event async def on_ready(): await bot.change_presence(activity=discord.Game(name=f"?help")) await asyncio.sleep(1) print("\n Bot has successfully logged in as: {}".format(bot.user)) print("Bot ID: {}\n".format(bot.user.id)) #run the bot try: bot.run(token) except discord.HTTPException as e: if e.status == 429: print("The Discord servers denied the connection for making too many requests") else: raise e
额外建议
- 确保discord.py版本是最新的,避免版本兼容问题:
pip install -U discord.py - 永远不要在代码中硬写token,使用
.env文件存储敏感信息更安全。
内容的提问来源于stack exchange,提问作者user19932233

