cog

时间:2021-02-09 04:34:08

标签: python command discord.py

我正在开发一个 Discord 机器人来抓取 reddit 上的帖子。现在我创建了一个命令,以便我可以使用@tasks.loop(time=y) 每 y 时间获取 x 数量的帖子。在 cog 中构建命令,将其加载到机器人中,它按预期工作。

现在我的问题是,据我所知,这个命令只能同时运行一个实例。即,如果我在服务器中运行该命令,它将正常工作,但在我 .cancel() 正在运行的实例之前,我将无法将该命令运行到另一台服务器中。

我想知道是否有办法让多个实例运行。就像命名循环或其他东西的方法,或者我是否应该使用 Discord.py 的另一个功能来实现我想要做的事情。

编辑: 为了简单起见,我在代码中省略了一些参数,但这里是有问题的代码

def launch_client():
bot = Bot()
reddit = client.Client()

bot.add_cog(ScheduleCog(bot, reddit))
class ScheduleCog(commands.Cog):
    time_unit = {'seconds': 1, 'minutes': 60, 'hours': 3600, 'days': 86400, 'weeks': 604800}
    def __init__(self, bot, reddit):
        self.bot = bot
        self.reddit = reddit

    def cog_unload(self):
        self.schedule_loop.cancel()

    @tasks.loop(seconds=1)
    async def schedule_loop(self, ctx, sub, sort, limit, time):
        posts = await self.reddit.get_posts(sub, sort, limit, time)

        if posts is not None:
            for post in posts:
                await ctx.channel.send(post.url)
        else:
            await ctx.channel.send('Error in your request. Please validate fields.')

    @schedule_loop.before_loop
    async def before_schedule_loop(self):
        await self.bot.wait_until_ready()

    @commands.command()
    async def subschedule(self, ctx, interval: int, interval_unit: str, sub: str, sort: str, limit: int,
                          time: str = 'hot'):
        unit: int = self.time_unit[interval_unit]
        self.schedule_loop.change_interval(seconds=interval * unit)
        self.schedule_loop.start(ctx, sub, sort, limit, time)

    @commands.command()
    async def subschedulestop(self, ctx):
        self.schedule_loop.cancel()

所以我已经按照官方的 discord.ext.tasks documentation 编写了这份协议。

现在一切都按预期进行循环。我启动 subschedule() 命令,它每隔“y”单位时间的“x”间隔发送帖子。

现在正如原始问题中所提到的,它可以在单个实例中工作,而我不知道如何拥有多个实例。我希望能够在不同的公会中运行多个 subschedule() 实例,甚至在同一个公会中运行多个实例,但是当我再次调用该命令时它现在可以工作,我收到运行时错误“任务已经启动但未完成” .

我只想知道能够并行运行多个任务的正确方法。

1 个答案:

答案 0 :(得分:0)

正如错误所说,如果它已经在运行,则不可能再次启动相同的循环,但您可以动态创建 tasks.Loop 的新实例

class TaskHandler(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self._tasks = [] # Empty list, holds all the loops. You can also use a dict if you want to differentiate the tasks somehow

    async def static_loop(self, *args):
        # This is the function that will be 'looping'
        print(args)

    def task_launcher(self, *args, **interval): # The `args` are the arguments passed into the loop
        """Creates new instances of `tasks.Loop`"""
        # Creating the task
        new_task = tasks.loop(**interval)(self.static_loop) # You can also pass a static interval and/or count
        # Starting the task
        new_task.start(*args)
        self._tasks.append(new_task)

    @commands.command()
    async def start_task(self, ctx, *args):
        """Command that launches a new task with the arguments given"""
        self.task_launcher(*args, seconds=1)
        await ctx.send('Task started!')

如果您还需要对 before/after_loop 的支持

new_task = tasks.loop(**interval)(self.static_loop) # You can also pass a static interval and/or count
# Adding before/after_loop functions
new_task.before_loop(BEFORE_LOOP_FUNCTION)
new_task.after_loop(AFTER_LOOP_FUNCTION)

如果您不了解装饰器的基础知识可能很难理解,如果是这样,您可以查看此Macro.expand/2