discord.py锁定所有频道的命令需要很长时间

discord.py Command for locking all channels takes a long time

我在我的 discord 机器人上有一个锁定频道的命令。锁定单个频道可以完美地工作,但是当我尝试锁定服务器中的所有频道时,这需要相当长的时间才能完成,具体取决于有多少频道。我不太确定是否有办法加快这个过程,但这是我的代码:

  async def send_m(self, ctx, check: bool):
      for c in ctx.guild.text_channels:
          if c.overwrites_for(ctx.guild.default_role).send_messages != check:
             await c.set_permissions(ctx.guild.default_role, send_messages = check)
            
  #lock
  @commands.check_any(commands.is_owner(), commands.has_permissions(manage_channels = True), commands.guild_only())
  @_channel.command(name="lock",
                   brief="Locks channel(s).",
                   help="Lock current/all channel(s)"
                   )
  async def _lock(self, ctx, channel=None):
      overwrite = ctx.channel.overwrites_for(ctx.guild.default_role)
      try:
          if channel == None and overwrite.send_messages != False:
              await ctx.channel.set_permissions(ctx.guild.default_role, send_messages = False)
              await ctx.send("Locked.")
          
          if channel == None and overwrite.send_messages == False:
              await ctx.send("This channel is already locked.")
      
          if channel == "all":
              await ctx.send(f"This will **lock** *all* channels. Type `{confirm}` to confirm.")
              def check(m):
                  return m.channel.id == ctx.channel.id and m.author.id == ctx.author.id
              try:
                  msg = await self.bot.wait_for("message", timeout=30, check=check)
              except asyncio.TimeoutError:
                  return await ctx.send("Time's up. Aborted.")
              if msg.content.lower() != confirm:
                  return await ctx.send("Aborted.")

              await ctx.send("Locking all channels...")
              await self.send_m(ctx=ctx, check=False)
              await ctx.send("Locked all channels ✅.")
      except Exception as e:
          raise e

如您所见,我尝试将其设为异步函数以查看是否有帮助,但没有用。难道我做错了什么?如有任何帮助,我们将不胜感激!

您编写了一个异步函数,但它并不是真正的运行异步。

async def send_m(self, ctx, check: bool):
    for c in ctx.guild.text_channels:
        if c.overwrites_for(ctx.guild.default_role).send_messages != check:
            await c.set_permissions(ctx.guild.default_role, send_messages = check)

await是阻塞操作。当您 运行 send_m 时,它会遍历通道并调用 c.set_permissions,等待每个调用完成后再继续下一个调用。

相反,您应该在等待任何事情之前用事件循环安排所有 c.set_permissions 调用。一种常见的方法是为每个任务创建一个任务,然后收集它们。

tasks = []
for c in ctx.guild.text_channels:
    if c.overwrites_for(ctx.guild.default_role).send_messages != check:
        tasks.append(asyncio.create_task(c.set_permissions(ctx.guild.default_role, send_messages=check)))
await asyncio.gather(*tasks)

这会让您得到想要的结果。但是,在这里使用 create_task 没有直接好处,因为您的 for 循环是同步的,并且 none 的任务无论如何都可以启动。您可以执行与上述相同的操作,但删除 create_task 调用。

tasks = []
for c in ctx.guild.text_channels:
    if c.overwrites_for(ctx.guild.default_role).send_messages != check:
        tasks.append(c.set_permissions(ctx.guild.default_role, send_messages=check))
await asyncio.gather(*tasks)