如何在 discord.py 机器人中正确使用任务/事件循环?

Posted

技术标签:

【中文标题】如何在 discord.py 机器人中正确使用任务/事件循环?【英文标题】:How do I correctly use tasks/the event loop in a discord.py bot? 【发布时间】:2021-05-14 19:27:12 【问题描述】:

我在这里阅读了答案,并尝试根据自己的使用情况对其进行调整: How to add a function to discord.py event loop?

我的情况如下:

我正在开发一个不和谐的机器人,我可以在其中运行一些用户可以运行的命令。这些命令可能会出错,在这种情况下,我会执行 client.loop.create_task(errorReportingFunction()),它会通过向我发送消息向我报告错误。我还有一个使用 asyncio.create_task() 代替的命令。

但是,我的内存泄漏从轻微到在长时间使用后使机器人崩溃不等,这导致我认为我没有正确使用任务系统。我是否应该在创建任务后进行清理,并在完成使用它们后以某种方式删除它们?或者有没有一个系统可以自动完成。

我也不确定 asyncio.create_task() 和 client.loop.create_task() 有何不同,所以我很感激一些关于何时使用的建议,或者它们是否基本相同。

【问题讨论】:

您为什么要为此使用任务?只在命令函数中运行代码有什么问题? 【参考方案1】:

我相信您想要在发生错误时做某事(例如发送消息)。如果是这样,在 discord.py 中有更好的方法来处理这个问题,而不是创建任务。

如果您只想对某个函数进行控制,您可以创建一个错误处理程序来跟踪从该函数引发的错误,并在发生错误时向您发送一条消息:

@bot.command()
async def info(ctx, *, member: discord.Member):
    """Tells you some info about the member."""
    fmt = '0 joined on 0.joined_at and has 1 roles.'
    await ctx.send(fmt.format(member, len(member.roles)))

@info.error
async def info_error(ctx, error):
    if isinstance(error, commands.BadArgument):
        await ctx.send('I could not find that member...')
    # Send a message to the bot owner about the error
    await self.bot.get_user(self.bot.owner_id).send('There has been an error in the command')

虽然 Discord 机器人的一个常见做法是拥有一个错误处理齿轮,它可以让您将所有错误处理集中在一个函数中。可能是这样的:

class ErrorCog(commands.Cog, name='Error'):
    '''Cog in charge of the error handling functions.'''

    def __init__(self, bot):
        self.bot = bot

    @commands.Cog.listener()
    async def on_command_error(self, ctx, error):
        '''Event that takes place when there is an error in a command.
    
        Keyword arguments:
        error -- error message '''

        error = getattr(error, 'original', error)
        
        # Wrong command
        if isinstance(error, commands.CommandNotFound):
            message = 'This is not a valid command'
            return await ctx.send(message)

        # Command is on cooldown
        elif isinstance(error, commands.CommandOnCooldown):
            if ctx.author.id is self.bot.owner_id:
                ctx.command.reset_cooldown(ctx)
                return await ctx.command.reinvoke(ctx)
            cooldowns = 
                commands.BucketType.default: f'for the whole bot.',
                commands.BucketType.user: f'for you.',
                commands.BucketType.guild: f'for this server.',
                commands.BucketType.channel: f'for this channel.',
                commands.BucketType.member: f'cooldown for you.',
                commands.BucketType.category: f'for this channel category.',
                commands.BucketType.role: f'for your role.'
            
            return await ctx.send(f'The command `ctx.command` is on cooldown cooldowns[error.cooldown.type] ')
        
        # Bot lacks permissions.
        elif isinstance(error, commands.BotMissingPermissions):
            permissions = '\n'.join([f'> permission' for permission in error.missing_perms])
            message = f'I am missing the following permissions required to run the command `ctx.command`.\npermissions'
            try:
                return await ctx.send(message)
            except discord.Forbidden:
                try:
                    return await ctx.author.send(message)
                except discord.Forbidden:
                    return

        # Here you need to add more instances
        # of errors according to your needs

def setup(bot):
    bot.add_cog(ErrorCog(bot))

【讨论】:

以上是关于如何在 discord.py 机器人中正确使用任务/事件循环?的主要内容,如果未能解决你的问题,请参考以下文章

Discord.py,如果它不存在,我将如何让机器人创建一个频道,但如果它确实存在,它将继续执行它的任务?

当命令 discord.py 的参数不正确时如何显示消息?

Discord py - 不同服务器上的相同机器人

在 discord.py 中删除机器人的消息

Discord.py 带线程,RuntimeError: Timeout context manager 应该在任务内部使用

如何使用 discord.py 在音乐机器人上获得最佳音频质量?