Discord.py脚本调用remove_roles/add_roles时运行缓慢问题求助
Discord.py角色分配操作导致性能缓慢的优化方案
核心问题分析
你遇到的性能问题根源在于:
- 循环中对每个成员单独调用
remove_roles()/add_roles(),每次调用都是一次Discord API请求,大量请求叠加导致等待时间过长 - 同步数据库查询阻塞异步事件循环,进一步拖慢执行速度
- 重复查询角色对象、执行不必要的角色操作(比如给已有角色的成员再次添加角色)
具体优化方案
1. 合并角色操作,避免重复API请求
remove_roles()和add_roles()支持一次性传入多个角色,同时先检查成员当前角色状态,只执行必要的变更:
- 比如黄金等级用户,可一次添加BRONZE和GOLD角色,一次移除VISITOR角色
- 先判断成员是否拥有目标角色,无则执行添加/移除,减少无效API调用
2. 批量查询数据库,减少IO次数
不要在循环中逐个查询用户订阅等级,改为一次性拉取所有活跃用户的Discord账号与对应等级,存入字典后直接查询:
# 批量查询所有活跃用户 db_cursor.execute("SELECT usrAccount, membership_level FROM vw_discord_active_members") active_members = {row[0]: row[1] for row in db_cursor.fetchall()}
之后循环成员时直接从active_members字典获取等级,避免多次数据库查询。
3. 提前初始化角色对象
将角色获取逻辑放在循环外部,无需每次while循环都重新获取角色:
async def updateActiveMemberRoles(): print('def executing') await client.wait_until_ready() guild = client.get_guild(913107079605141525) # 只初始化一次角色对象 ROLE_GOLD = guild.get_role(991694541298090059) ROLE_BRONZE = guild.get_role(914277751719096381) ROLE_VISITOR = guild.get_role(914280052424859700) while not client.is_closed(): # 后续循环直接使用已初始化的角色 ...
4. 替换同步数据库驱动为异步版本
mysql.connector是同步库,在异步函数中调用会阻塞事件循环。改用aiomysql异步驱动,让数据库查询不影响Discord API操作的并发执行。
优化后的完整代码示例
import asyncio import discord import aiomysql import os from dotenv import load_dotenv load_dotenv() BOT_TOKEN = os.getenv("DISCORD_TOKEN") async def updateActiveMemberRoles(): print('def executing') await client.wait_until_ready() guild = client.get_guild(913107079605141525) # 提前初始化角色 ROLE_GOLD = guild.get_role(991694541298090059) ROLE_BRONZE = guild.get_role(914277751719096381) ROLE_VISITOR = guild.get_role(914280052424859700) # 异步数据库连接配置 db_config = { 'host': os.getenv("DB_HOST"), 'user': os.getenv("DB_USER"), 'password': os.getenv("DB_PASSWORD"), 'db': os.getenv("DB_NAME"), 'autocommit': True } while not client.is_closed(): # 批量查询所有活跃用户 async with aiomysql.connect(**db_config) as conn: async with conn.cursor() as cur: await cur.execute("SELECT usrAccount, membership_level FROM vw_discord_active_members") active_members = {row[0]: row[1] for row in await cur.fetchall()} for member in guild.members: discord_tag = f"{member.name}#{member.discriminator}" print(discord_tag) membership_level = active_members.get(discord_tag) if membership_level: print(f"{discord_tag} {membership_level}") if membership_level == "gold": # 检查并执行必要的角色变更 if ROLE_VISITOR in member.roles: await member.remove_roles(ROLE_VISITOR) # 一次性添加多个角色 await member.add_roles(ROLE_BRONZE, ROLE_GOLD) print("gold") elif membership_level == "bronze": if ROLE_VISITOR in member.roles: await member.remove_roles(ROLE_VISITOR) if ROLE_GOLD in member.roles: await member.remove_roles(ROLE_GOLD) await member.add_roles(ROLE_BRONZE) print("bronze") else: # 移除高级角色,添加访客角色 roles_to_remove = [role for role in [ROLE_BRONZE, ROLE_GOLD] if role in member.roles] if roles_to_remove: await member.remove_roles(*roles_to_remove) if ROLE_VISITOR not in member.roles: await member.add_roles(ROLE_VISITOR) print("visitor") print("------------------------------") print("--- Wait 60 Seconds ----------") print("------------------------------") await asyncio.sleep(60) intents = discord.Intents.default() intents.members = True client = discord.Client(intents=intents) @client.event async def on_ready(): print("Bot is ready.") client.loop.create_task(updateActiveMemberRoles()) client.run(BOT_TOKEN)
内容的提问来源于stack exchange,提问作者mario
相关产品推荐
相关产品推荐

