游戏服务器排行榜的设计

来源:互联网 发布:软文写作 知乎 编辑:程序博客网 时间:2024/04/30 05:23

排行榜是游戏服务器中不可缺少的一部分,几乎所有的游戏都有排行榜。游戏排行榜根据排行榜需要上榜的人数有不同的设计,但是普遍来说一般都是显示前100名或者50名,排行榜排100,1k,1w人数,超过1w名次的很少需要进行排名不过也不排除特别的排行榜。下面设计的排行榜可以满足1w名以内的排行榜,并且是实时排行榜。超过1w估计就的用其他的解决办法了。其实排行榜可以直接用数据库,nosql,静态链表,map,数组等方法进行设计,而且这些方法除nosql外我都在项目中使用过。下面介绍的是最普通的排行榜实现,数组实现。也许有人会说数组会不会导致性能问题,其实以我自己的经验来说没有任何问题,当然排行榜人数不能超过1w,本人亲自在以前的项目中使用过,项目同时在线人数最高2w,排行榜没有出现任何性能问题。下面是数组排行榜的代码,很简单,轻松实现,想改就改。不说了上代码:

//.h文件

struct ListNote
{
uint32_t  roleID;
int32_t nValue;
uint8_t nLastRank;
char szRoleName[enmMaxRoleNameLength];
};
class  CRank
{
enum 
{
RANKMAX = 5000,
};
public:
CRank();
~CRank();
int32_t Initialize();
int32_t Insert(const uint32_t roleID,const int32_t nValue);
private:
ListNote m_arrNote[RANKMAX];
int32_t m_nCount;
bool m_bSave;
};

/////cpp文件

CRank::CRank()
{
Initialize();
}
CRank::~CRank()
{
}
int32_t CRank::Initialize()
{
memset(m_arrNote,0,sizeof(m_arrNote));
m_nCount = 0;
m_bSave = false;
return S_OK;
}
int32_t CRank::Insert(const uint32_t roleID,const int32_t nValue)
{
if (RANKMAX == m_nCount && nValue <= m_arrNote[RANKMAX-1].nValue) return S_OK;
int32_t nRoleIndex = -1;
int32_t nInsertIndex = -1;
for (int32_t i = 0; i < m_nCount;++i)
{
if(nValue <= m_arrNote[i].nValue) nInsertIndex = i;
if (roleID == m_arrNote[i].roleID)
{
if (nValue <= m_arrNote[i].nValue) return S_OK;
nRoleIndex = i;
break;
}
}
m_bSave = true;
++nInsertIndex;
if (nRoleIndex == nInsertIndex)
{
m_arrNote[nRoleIndex].nValue = nValue;
return S_OK;
}
int32_t nTempIndex = m_nCount;
if(-1 != nRoleIndex) nTempIndex = nRoleIndex;
for (int32_t i = nInsertIndex; i < nTempIndex; ++i)
{
m_arrNote[i].nLastRank = i+1;
}
int32_t nCount = m_nCount - nInsertIndex;
if(-1 != nRoleIndex) nCount = nRoleIndex - nInsertIndex;
if(RANKMAX == m_nCount && -1 == nRoleIndex) --nCount;
if (nCount > 0)
{
memmove(&m_arrNote[nInsertIndex+1],&m_arrNote[nInsertIndex],sizeof(ListNote)*nCount);
}
m_arrNote[nInsertIndex].nValue = nValue;
m_arrNote[nInsertIndex].roleID = roleID;
m_arrNote[nInsertIndex].nLastRank = 0;
if(-1 != nRoleIndex)m_arrNote[nInsertIndex].nLastRank = nRoleIndex+1;
else
{
if(m_nCount < RANKMAX) ++m_nCount;
}
return S_OK;
}

//main cpp文件

CRank *test = new CRank();
const uint32_t nSize = 100000;
uint32_t arrValue[nSize]={0};
uint32_t arrValue1[nSize]={0};
for (uint32_t i = 0; i < nSize;++i)
{
arrValue[i] = i+1;
}
random_shuffle(arrValue,&arrValue[nSize]);
for (uint32_t i = 0; i< nSize;++i)
{
arrValue1[i] = arrValue[i]+100;
}
uint64_t nBeginTime = CDateTime::CurrDateTime().GetMicroseconds();
for (uint32_t i = 0; i < nSize;++i)
{
test->Insert(i+1,arrValue[i]);
}
for (uint32_t i = 0; i < nSize;++i)
{
test->Insert(i+1,arrValue1[i]);
}
uint64_t nEndTime =  CDateTime::CurrDateTime().GetMicroseconds();
WRITE_ERROR_LOG("use time=%d",nEndTime-nBeginTime);

排行榜人数为100人的时候进行20w次insert的平均时间不到1微妙 ,排行榜1w人的时候进行20w次插入平均时间在10微妙左右。当然时间还和ListNote结构体大小有关系。因为结构体越大每次memmove的数据就会越多。其实也可以做指针数组这样每次memmove的数据比较小,所以这样设计的排行榜对多数游戏服务器排行榜都能满足要求而且还是内存实时排。如果排行榜要求上榜的人数较多又需要实时排行榜那可以用静态链表实现,以前项目中排行榜就有三四十个而且全部是实时排行榜,每个排行榜上榜1w就是使用静态链表实现的,没有出现过性能问题。

0 0