【问题标题】:Discord.py avoid blocking on_message methodDiscord.py 避免阻塞 on_message 方法
【发布时间】:2021-09-24 17:58:15
【问题描述】:

我正在开发一个主要处理图像的 Discord 机器人。到目前为止它正在工作,但是当一次发送多个图像时,我遇到了很多阻塞和不一致。

是这样的:

用户上传图片 > 机器人在消息上放置“眼睛”表情符号 > 机器人处理图像 > 机器人响应结果。

但是,有时它可以一次处理多张图像(机器人将眼睛表情符号放在前几张图像上),但通常它只是将表情符号放在第一张图像上,然后在完成那张图像后,它会处理接下来的 2-3图片等

花费大部分时间的过程是OCR读取图像。

这是一些抽象代码:

main.py

@client.event
async def on_message(message):
  ...
  if len(message.attachments) > 0: await message_service.handle_image(message)
  ...

message_service.py

  async def handle_image(self, message):
    supported_attachments = filter_out_unsupported(message.attachments)
    images = []
    await message.reply(f"{random_greeting()} {message.author.mention}, I'm processing your upload(s) please wait a moment, this could take up to 30 seconds.")
    await message.add_reaction('????')
    for a in supported_attachments:
      async with aiohttp.ClientSession() as session:
        async with session.get(a) as res:
          if res.status == 200:
            buffer = io.BytesIO(await res.read())
            arr = np.asarray(bytearray(buffer.read()), dtype=np.uint8)
            images.append(cv2.imdecode(arr, -1))

          for image in images:
            result = await self.image_handler.handle_image(image, message.author)
            await message.remove_reaction('????', message.author)
            if result == None:
              await message.reply(f"{message.author.mention} I can't process your image. It's incorrect, unclear or I'm just not smart enough... :(")
              await message.add_reaction('❌')
            else:
              await message.reply(result)

image_handler

async def handle_image(self, image, author):
    try:
      if image is None: return None

      governor_id = str(self.__get_governor_id_by_discord_id(author.id))
      if governor_id == None:
        return f"{author.mention} there was no account registered under your discord id, please register by using this format: `$register <governor_id> <in game name>`, for example: `$register ... ...`. After that repost the screenshot.\n As for now multiple accounts are not supported."
      
      # This part is most likely the bottleneck !!
      read_result = self.reader.read_image_task(image)
      if self.__no_values_are_found(...):
        return None

      return self.sheets_client.update_player_row_in_sheets(...)
    except:
      return None
    
  def __no_values_are_found(self, *args):
    return all(v is None for v in [*args])


  def __get_governor_id_by_discord_id(self, id):
    return self.sheets_client.get_governor_id_by_discord_id(id)

总的来说,我是 Python 和 Discord 机器人的新手,但有没有一种干净的方法来处理这个问题?

我一直在考虑线程,但在这种情况下似乎找不到很多解决方案,这让我相信我错过了什么或做某事效率低下。

【问题讨论】:

    标签: python python-3.x discord discord.py


    【解决方案1】:

    其实有一个干净的方法,你可以创建自己的to_thread装饰器并装饰你的阻塞函数(虽然它们不能是协程,但它们必须是普通的同步函数)

    import asyncio
    from functools import partial, wraps
    
    def to_thread(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            loop = asyncio.get_event_loop()
            callback = partial(func, *args, **kwargs)
            return await loop.run_in_executor(None, callback)  # if using python 3.9+ use `await asyncio.to_thread(callback)`
        return wrapper
    
    
    # usage
    @to_thread
    def handle_image(self, image, author):  # notice how it's *not* an async function
        ...
    
    
    # calling
    await handle_image(...)  # not a coroutine, yet I'm awaiting it (cause of the wrapper function)
    

    【讨论】:

    • 注意:你也可以使用aioify.aioify - pip install aoify - 如果你只是想使用一个库(或多或少做同样的事情)
    • 我对那个库不是很熟悉,但是看起来差不多,谢谢你的建议
    • @ŁukaszKwieciński 感谢您的快速回复!我正在尝试并遇到以下问题:TypeError: run_until_complete() takes 2 positional arguments but 3 were given 当我删除第一个参数(无)时,我得到:..../base_events.py", line 578, in _check_running raise RuntimeError('This event loop is already running')
    • 我的错。应该是run_in_executor,抱歉
    • 太棒了,似乎有效。非常感谢! @ŁukaszKwieciński
    猜你喜欢
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-17
    • 2012-11-25
    • 1970-01-01
    • 2015-09-27
    相关资源
    最近更新 更多