【问题标题】:Can I make the python code work while sorting list我可以在排序列表时使python代码工作吗
【发布时间】:2021-11-01 05:15:19
【问题描述】:

我在 discord.py 上做了一个 top 命令(使用 Replit 数据库)。基本上显示了服务器中 XP 最多的前 10 名用户。

这就是我的一部分代码的样子,忽略我将密钥保存到数据库的混乱方式

@commands.command()
async def top(self,ctx,nr:int=1):
      match_keys = db.prefix(f"{ctx.guild.id}XP")
      sort = sorted(match_keys, key=lambda x: db[x],reverse=True)
[...]

我有 2000 个密钥来排序,整个过程大约需要 10 秒才能完成。在这 10 秒内,机器人无法使用。我已经测试过了,唯一需要时间的是排序。我在 StackOverflow 上看到了其他类似的问题,但从我在那里发现的情况来看,排序/排序方法是基于快速排序的,为了更快,我真的做不了什么。

我正在考虑创建一个任务循环,它会不时更新顶部(运行 .top 命令时等待的时间更少),但机器人在对列表进行排序时将无法使用。

是否可以减慢排序速度,以便在操作时使用机器人?谢谢!

抱歉可能出现的错误,我是 stackoverflow 的新手

【问题讨论】:

  • 什么是dbdb[x] 是做什么的?
  • 对 2000 个元素本身进行排序应该几乎是瞬间完成的,但它需要调用你的 key 函数超过 2000 次,所以如果 db[x] 查找速度很慢,排序也会很慢。 (为了证明排序有多快,运行 sorted(reversed(range(2000))) -- 不到 10 秒,对吧?)
  • @Macattack db 是从数据库中获取值的预定义方式。如果我在数据库中保存一个名为“XP”的键并将其值 23,当我调用 db["XP'] 时,它应该检索值 23。但是我代码中的 db[x] 是自定义键排序。key=lambda x:db[x] 表示对于列表中的每个 X 项目,它都会对 X 的数据库值进行排序(如果列表是 {"XP", "cactuses"},它将对 db[" 的值进行排序XP"] 和 db["cactuses"]。数据库的东西与这个问题无关,但我希望我能以某种方式帮助
  • @DenisDenis 2000 数据库查询每次只获取 1 个项目将非常慢。相反,您应该执行 one 查询以(预)获取 all 项,然后将这些内存值用于 key 函数。
  • 我从命名和使用中猜测 Replit db 正在使用,它似乎不支持多键/批量获取。支持将整个数据库转储到字典(数据库中限制为 5000 个键:值),这样可以更快。虽然有点用霰弹枪杀死一只苍蝇,但如果这就是你所拥有的。

标签: python sorting discord.py


【解决方案1】:

为了避免长时间运行的同步任务阻塞事件循环(从而阻塞async 应用程序),可以直接将它们卸载到线程。事实上,asyncio 已经有一个可以运行此类任务的内置线程池。

从 Python3.9 开始,asyncio.to_thread 让这变得很方便:

import asyncio

@commands.command()
async def top(self,ctx,nr:int=1):
      match_keys = db.prefix(f"{ctx.guild.id}XP")
      sort = await asyncio.to_thread(
          sorted, match_keys, key=lambda x: db[x], reverse=True
      )

早期版本可以改用asyncioloop.run_in_executor

import asyncio
from functools import partial

@commands.command()
async def top(self,ctx,nr:int=1):
      match_keys = db.prefix(f"{ctx.guild.id}XP")
      loop = asyncio.get_running_loop()
      sort = await loop.run_in_executor(
          None,
          partial(sorted, match_keys, key=lambda x: db[x], reverse=True),
      )

【讨论】:

    【解决方案2】:

    我从 cmets 了解到,您的数据库不支持多键/批量查询。但是,您仍然可以采取一些方法,例如cachingawaitable remote procedures、转储整个数据库等。

    一个快速的解决方案可能是将查询数据库与对条目进行排序分开,这样您就可以使用异步函数 - 而不是阻塞整个十秒。

    async def get_entries(match_keys):
        entries = {}
        for key in match_keys:
            entries[key] = db[key]
            await asyncio.sleep(0) # yield control to the event loop
        return entries
    
    @commands.command()
    async def top(self, ctx, nr:int=1):
          match_keys = db.prefix(f"{ctx.guild.id}XP")
          entries = await get_entries(match_keys)
          sort = sorted(entries.items(), key=lambda e: e[1], reverse=True)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-19
      • 1970-01-01
      • 2017-12-27
      • 2013-09-16
      • 2014-09-14
      • 1970-01-01
      相关资源
      最近更新 更多