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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:09:59