我有一个Player
类,其score
属性:
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
答案 0 :(得分:6)
Redis排序集帮助解决了这个问题(文档使用排行榜作为示例用法)http://redis.io/topics/data-types-intro#redis-sorted-sets
Redis可以用作玩家排名的缓存。应用程序启动时,从SQL数据中填充redis。在mysql中更新玩家分数时也会更新redis。
如果您有多个服务器进程/线程并且它们可以同时触发玩家得分更新,那么您还应该考虑mysql / redis更新竞争条件,例如:
答案 1 :(得分:4)
您遇到的问题是您希望对数据库进行实时更新,每次都需要进行数据库查询。如果您在内存中保留一个分数列表,并以更合理的频率更新(例如每小时一次,甚至每分钟一次,如果您的玩家真的关心他们的等级),那么玩家仍将体验真实的时间进度与得分排名,他们无法确定更新中是否存在短暂滞后。
通过内存中的分数排序列表,您可以立即获得玩家的等级(即时,我的意思是内存中的O(lg n)查找),代价是要缓存的内存,当然还有时间到您希望更新缓存。与每次有人想要查看其排名的100k记录的db查询相比,这是一个更好的选择。
在排序列表上详细说明,您必须查询数据库以获取它,但您可以继续使用它一段时间。也许你存储了last_update,并且只有当这个列表“太旧”时才重新查询数据库。所以你不要一直尝试更新,而是快速更新,而只是觉得它就像是实时的。
为了几乎立即找到某人的排名,您可以使用bisect模块,该模块支持在排序列表中进行二进制搜索。得分时会对分数进行排序。
from bisect import bisect_left
# suppose scores are 1 through 10
scores = range(1, 11)
# get the insertion index for score 7
# subtract it from len(scores) because bisect expects ascending sort
# but you want a descending rank
print len(scores) - bisect_left(scores, 7)
这表示7分是4级,这是正确的。
答案 2 :(得分:0)
可以使用SQLAlchemy的sort_by函数来提取这类信息。如果您执行如下查询:
<?php
if(isset($_POST['create_post'])){
$post_title = $_POST['title'];
$post_author = $_POST['authror'];
$post_category_id= $_POST['post_category_id'];
$post_status = $_POST['post_status'];
$post_image = $_FILES['image']['name'];
$post_image_temp = $_FILES['image']['tmp_name']; // this is change
$post_tags= $_POST['post_tags'];
$post_content = $_POST['post_content'];
$post_date = date('d-m-y');
$post_comment_count = 4;
move_uploaded_file($post_image_temp, "../images/$post_image");
}
?>
<form action = "" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="title"> Title</label>
<input type="text" class="form-control" name="title">
</div>
<div class="form-group">
<label for="Category"> Category</label>
<input type="text" class="form-control" name="category">
</div>
<div class="form-group">
<label for="Author"> Author</label>
<input type="text" class="form-control" name="author">
</div>
<div class="form-group">
<label for="post-status"> Status</label>
<input type="text" class="form-control" name="post_status">
</div>
<div class="form-group">
<label for="post_image"> Image</label>
<input type="file" name="image">
</div>
<div class="form-group">
<label for="post_tags"> Tags</label>
<input type="text" class="form-control" name="post_tags">
</div>
<div class="form-group">
<label for="post_content"> Content</label>
<textarea type="text" class="form-control" name="post_content" id="" cols="30" rows="10"></textarea>
</div>
<div class="form-group">
<input class="btn btn-primary" type="submit" name="create_post" value="publish post">
</div>
</form>
您将按照分数排序玩家列表。请记住,每次执行此操作时,都要使用数据库执行I / O操作,这可能会相当慢,而不是保存数据python变量。