一个游戏服务器进程,需要维护数以千计的角色,每个角色都有大量的数据,
角色的固有信息、角色的不断改变的状态信息、角色的物品、好友、任务
等等,另外进程还需要维护大量的地图信息、地图上的npc、monster等等,
这些东西的创建、销毁、更新、检索需要耗费大量的cpu时间。
为了让服务器的性能更好,能更快的响应客户端,服务更多的客户端,必须
尽量减少这些过程所耗用的cpu时间。
我们知道,对于服务器来说,瓶颈在运算能力而非内存,加一颗cpu的钱可
以加1G以上的内存,另外加cpu需要主板及更多的硬件支持,所以可以遵循
内存换效率的原则。
对于对象的创建和销毁,我们可以通过预先创建,滞后销毁等方法来避免
可观的开销。至于对象更新,基本上不可避免,也很难从原则上减少计算。
对于检索或者说定位对象,则可以用一些技巧来显著提高效率。
平衡二叉树是一个能比较快的定位一个成员的组织结构。例如:
我们存放一个角色列表 map< RoleID, CRole* > mapRole;
当一个玩家对另一个玩家产生交互的时候,只需要提供对方的RoleID,
我们可以很快的检索到对方的CRole*,来完成相应的逻辑运算。
假设mapRole有1000个成员,最坏的情况我们定位到CRole*需要比较
大约10次(2的10次方位1024),当然还有Iterator运算的开销。
这是一个很漂亮的做法,效率也很高了。
还能更高么?
如果不能再高那我就不会写这篇文章了。 :)
答案是-------------------数组。
CRole* array[1000];
然后在每个CRole中记录下自己在array中的下标(这是这种做法不漂亮的地方),
当一个玩家与另外一个玩家交互时,只需要提供对方数组下标即可,服务器
用下标直接定位,无需检索,比较次数为 零
!。不检索才是最快的检索 :)
说说这种做法不漂亮的地方,
1。需要在CRole中记录自己在array中的下标,我们要维护这种对应关系,这
违背常规的设计准则,因为一旦关系乱了,就歇菜了。
其实说白了,所谓的维护,其实工作很简单,在创建CRole的时候把下标
给他,永远不需要修改,也不允许修改。那么出错的机会就不存在了。
规则是死的,人是活的。所有的事情都按照规则办,就什么事都做不成。
我们要的是效率,要的是结果,准则、规则、规范,那都是为了避免在达到
结果的过程中犯错误而总结归纳出来的,其目的也是为了更好的达到结果。
我们要保持一颗Open的心,有了一颗Open的心,那就不再是程序员了,
而是高手程序员了。
2。要把下标告知可能需要的其他客户端。
这个其实根本就不是问题,能把RoleID给其他客户端,为什么不能把
下标也给它呢?
还是那句话,需要一颗Open的心......
这种做法还有一个问题需要注意:
为了避免张冠李戴,客户端提供下标的同时需要提供RoleID,这样服务器
可以对该下标处存放的CRole是否确实其期望交互的对象作一个验证。
这种做法其实可以广泛应用于服务器程序的各个模块,比如地图管理自己里面
的npc,monster,甚至是特效对象。
当然,最好是用一个类将此数组及相关的方法包装起来。这里重在说明原理,
不再细说。