【发布时间】:2016-12-21 19:53:29
【问题描述】:
我有一个带有score 属性的Player 类:
class Player(game_engine.Player):
def __init__(self, id):
super().__init__(id)
self.score = 0
随着玩家成功/失败完成目标,该分数会增加/减少。现在我需要告诉玩家他在玩家总数中的排名,比如
print('Your rank is {0} out of {1}')
首先我想有一个所有玩家的列表,以及每当玩家发生任何事情时:
- 我检查他的分数是增加还是减少
- 在列表中找到他
- 移动他,直到他的分数在正确的位置
但这会非常慢。可能有数十万玩家,玩家可以将自己的分数重置为0,这意味着我必须将堆栈中的每个人都移到他之后。即使找到玩家也是 O(n)。
我正在寻找的是一种高性能的解决方案。尽管应该使用常识,但 RAM 的使用并不那么重要。我怎样才能将系统改进得更快?
更新信息:每次玩家离开游戏服务器时,我都会使用 SQLAlchemy 将玩家的数据存储到 MySQL 数据库中,并在每次他加入服务器时加载它。这些是通过'player_join' 和'player_leave' 事件处理的:
@Event('player_join')
def load_player(id):
"""Load player into the global players dict."""
session = Session()
query = session.query(Player).filter_by(id=id)
players[id] = query.one_or_none() or Player(id=id)
@Event('player_leave')
def save_player(id):
"""Save player into the database."""
session = Session()
session.add(players[id])
session.commit()
此外,玩家的分数会根据'player_kill' 事件更新:
@Event('player_kill')
def update_score(id, target_id):
"""Update players' scores upon a kill."""
players[id].score += 2
players[target_id].score -= 2
【问题讨论】:
-
您使用哪个数据库?
-
@r-m-n 我正在使用 MySQL
-
在某些数据库中可以使用 DENSE_RANK 窗口函数来完成,但 MySQL 不支持此函数。你可以试试这样dukesoftware00.blogspot.ru/2012/11/…
-
我已经使用 redis 排序集处理了这个问题 - 例如,有一些简单的命令可以获取特定键的等级,并且 redis 将比您尝试构建自己的任何东西都快得多,而无需大量投资。
-
你可以有一个每小时的任务来制作一个排序的分数列表,这将允许你快速确定当前的排名,比如缓存列表上的 bisect.bisect_left。分数列表不需要完整——也许保留每 1000 个分数。您可以去 db 获取实际顶级玩家的准确排名。
标签: python algorithm python-3.x ranking rank