玩家属性同步优化-脏数据标记(位运算、数组、stl之bitset)
把大神的帖子中一部分摘抄出来,结合自己写的位运算代码和循环代码(数组遍历)进行性能测试分析并给出结果。 摘自: https://www.gameres.com/827195.html
本文适用于所有脏标记遍历功能,提升性能几倍,本文以游戏中玩家的属性同步作为例子进行介绍。
先说性能分析结果:一般玩家属性列表也就120个够用了,其中常用的攻击,防御,血蓝等,不超过20个。每0.5秒同步一次,那么变化的常用属性更少。
当变化10个属性,位运算性能提升6倍,20个时4倍,如图所示:

总结:位运算效率高,并且把常用属性定义为低位效率更高。 其次是数组(原因是遍历),再其次是set(影响原因是hash函数、hash扩容、二叉树节点转换),最差是stl之bitset(原因:本质也是数组)
优化前的循环算法(数组):
const int N = ;
class BitSet
{
public:
BitSet()
{
memset(m_szBits,,sizeof(m_szBits));
m_bBitsDirty = false;
}
int Set(size_t i)
{
if(i >= && i < N)
{
++m_szBits[i]; m_bBitsDirty = true; }
return ;
}
int Get(size_t i) const
{
if(i >= && i < N)
{
return m_szBits[i] > ;
}
return ;
}
void Clean()
{
memset(m_szBits,,sizeof(m_szBits));
m_bBitsDirty = false;
}
bool IsDirty() const
{
return m_bBitsDirty;
}
private:
char * m_szBits[N];
bool m_bBitsDirty;
};
优化后的位运算:
const int nLLLeng = ;
class NewBitSet
{
public:
NewBitSet():llLow(0ull),llHight(0ull)
{
}
void Set(size_t i)
{
if(i > && i < nLLLeng)
{
llLow |= 1ull << i;
}
else if (i < nLLLeng * )
{
llHight |= 1ull << (i & 0x3F); // 0x3F 是64的16进制,这样做是相当于减64
}
}
void GetAllDirty(int * arrDirty, int & nMaxCount) const
{
unsigned long long nllLowTemp = llLow;
unsigned long long nllHightTemp = llHight;
nMaxCount = -;
while (nllLowTemp)
{
arrDirty[++nMaxCount] = __builtin_ffsll(nllLowTemp) - ;
nllLowTemp &= (nllLowTemp - );
}
while (nllHightTemp)
{
arrDirty[++nMaxCount] = __builtin_ffsll(nllHightTemp) - + nLLLeng;
nllHightTemp &= (nllHightTemp - );
}
}
void Clean()
{
llLow = llHight = 0ull;
} bool IsDirty() const
{
return llLow || llHight;
}
private:
unsigned long long int llLow;
unsigned long long int llHight;
};
测试用例:
#include <iostream>
#include <sys/time.h>
#include<stdlib.h>
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<map>
#include <string.h>
using namespace std;
const int N = ;
class BitSet
{
public:
BitSet()
{
memset(m_szBits,,sizeof(m_szBits));
m_bBitsDirty = false;
}
int Set(size_t i)
{
if(i >= && i < N)
{
++m_szBits[i]; m_bBitsDirty = true; }
return ;
}
int Get(size_t i) const
{
if(i >= && i < N)
{
return m_szBits[i] > ;
}
return ;
}
void Clean()
{
memset(m_szBits,,sizeof(m_szBits));
m_bBitsDirty = false;
}
bool IsDirty() const
{
return m_bBitsDirty;
}
private:
char * m_szBits[N];
bool m_bBitsDirty;
}; const int nLLLeng = ;
class NewBitSet
{
public:
NewBitSet():llLow(0ull),llHight(0ull)
{
}
void Set(size_t i)
{
if(i > && i < nLLLeng)
{
llLow |= 1ull << i;
}
else if (i < nLLLeng * )
{
llHight |= 1ull << (i & 0x3F); // 0x3F 是64的16进制,这样做是相当于减64
}
}
void GetAllDirty(int * arrDirty, int & nMaxCount) const
{
unsigned long long nllLowTemp = llLow;
unsigned long long nllHightTemp = llHight;
nMaxCount = -;
while (nllLowTemp)
{
arrDirty[++nMaxCount] = __builtin_ffsll(nllLowTemp) - ;
nllLowTemp &= (nllLowTemp - );
}
while (nllHightTemp)
{
arrDirty[++nMaxCount] = __builtin_ffsll(nllHightTemp) - + nLLLeng;
nllHightTemp &= (nllHightTemp - );
}
}
void Clean()
{
llLow = llHight = 0ull;
} bool IsDirty() const
{
return llLow || llHight;
}
private:
unsigned long long int llLow;
unsigned long long int llHight;
}; int nPrintCount = ; void DirtyBit(int nRandCount)
{
NewBitSet tDirty;
int nRand = ;
//srand((unsigned)time(0));
for (int i = ; i < nRandCount;i++)
{
// nRand = rand()%126 + 1;
tDirty.Set(i+);
}
if (!tDirty.IsDirty())
{
return;
}
int arrDirty[nLLLeng * ] = {};
//同步自己执行次数
int nMaxCount = ;
tDirty.GetAllDirty(arrDirty, nMaxCount);
nMaxCount = ;
//同步WS执行次数
tDirty.GetAllDirty(arrDirty, nMaxCount); int nNotPrint = ;
for (int i = ; i< nMaxCount; i++)
{
nNotPrint = arrDirty[i];
}
tDirty.Clean();
} void DirtyArr(int nRandCount)
{
BitSet tDirty;
int nRand = ;
// srand((unsigned)time(0));
for (int i = ; i < nRandCount;i++)
{
// nRand = rand()%126 + 1;
tDirty.Set(i+);
}
if (tDirty.IsDirty())
{
int arrDirty[N] = {};
int nMaxCount = -;
//同步自己执行次数
for (int i = ; i< N; ++i)
{
if (tDirty.Get(i))
{
arrDirty[++nMaxCount] = i;
}
}
//同步WS执行次数
nMaxCount = -;
for (int i = ; i< N; ++i)
{
if (tDirty.Get(i))
{
arrDirty[++nMaxCount] = i;
}
}
int nNotPrint = ;
for (int i = ; i< nMaxCount + ; i++)
{
nNotPrint = arrDirty[i];
}
} tDirty.Clean();
} int main()
{
float time_use=;
struct timeval start;
struct timeval end;
int nTestCount = ;
gettimeofday(&start,NULL); nPrintCount = ;
//处理过程--开始
for (int i = ; i< ; ++i)
{
DirtyBit(nTestCount);
}
//处理过程--结束 cout<<endl;
gettimeofday(&end,NULL);
time_use=(end.tv_sec-start.tv_sec)*+(end.tv_usec-start.tv_usec);//微秒
printf("time_use is %.10f\n",time_use); nPrintCount = ;
gettimeofday(&start,NULL);
//处理过程--开始
for (int i = ; i< ; ++i)
{
DirtyArr(nTestCount);
}
//处理过程--结束 cout<<endl;
gettimeofday(&end,NULL); time_use=(end.tv_sec-start.tv_sec)*+(end.tv_usec-start.tv_usec);//微秒
printf("time_use is %.10f\n",time_use);
return ;
}
玩家属性同步优化-脏数据标记(位运算、数组、stl之bitset)的更多相关文章
- C++基础-位运算
昨天笔试遇到一道题,让实现乘法的计算方法,设计方案并优化,后来总结位运算相关知识如下: 在计算机中,数据是以1010的二进制形式存储的,1bytes = 8 bits,bit就是位,所以位运算就是对每 ...
- C/C++中的位运算
位运算 位运算的运算分量只能是整型或字符型数据,位运算把运算对象看作是由二进位组成的位串信息,按位完成指定的运算,得到位串信息的结果. 位运算符有: &(按位与).|(按位或) ...
- P3613 睡觉困难综合征 LCT+贪心+位运算
\(\color{#0066ff}{ 题目描述 }\) 由乃这个问题越想越迷糊,已经达到了废寝忘食的地步.结果她发现--晚上睡不着了!只能把自己的一个神经元(我们可以抽象成一个树形结构)拿出来,交给D ...
- STL+位运算的文件
1.queue 队列 queue的头文件是<queue>. 定义queue对象的示例代码如: queue<int>q; 队列内存放的是int类型的数 queue<dou ...
- 一文了解有趣的位运算(&、|、^、~、>>、<<)
1.位运算概述 从现代计算机中所有的数据二进制的形式存储在设备中.即0.1两种状态,计算机对二进制数据进行的运算(+.-.*./)都是叫位运算,即将符号位共同参与运算的运算. 口说无凭,举一个简单的例 ...
- 位运算(&、|、^、~、>>、<<)
1.位运算概述 从现代计算机中所有的数据二进制的形式存储在设备中.即0.1两种状态,计算机对二进制数据进行的运算(+.-.*./)都是叫位运算,即将符号位共同参与运算的运算. 口说无凭,举一个简单的例 ...
- 原生Redis跨数据中心双向同步优化实践
一.背景 公司基于业务发展以及战略部署,需要实现在多个数据中心单元化部署,一方面可以实现多数据中心容灾,另外可以提升用户请求访问速度.需要保证多数据中心容灾或者实现用户就近访问的话,需要各个数据中心拥 ...
- Angular 1 深度解析:脏数据检查与 angular 性能优化
TL;DR 脏检查是一种模型到视图的数据映射机制,由 $apply 或 $digest 触发. 脏检查的范围是整个页面,不受区域或组件划分影响 使用尽量简单的绑定表达式提升脏检查执行速度 尽量减少页面 ...
- 关于位图数据和标记位-P3
文章目录 1 背景 1.1 问题 2 问题1探究 2.1 没有区的情况 2.2 一个区的情况 2.3 两个区的情况 2.4 三个区的情况 2.5 四个区的情况 2.6 五个区的情况 3 问题2探究 3 ...
随机推荐
- SOFT-NMS (二) (non maximum suppression,非极大值抑制)
import numpy as np boxes = np.array([[200, 200, 400, 400], [220, 220, 420, 420], [200, 240, 400, 440 ...
- P1361 小M的作物 (最大流)
题目 P1361 小M的作物 解析 把\(A\)看做源点,把\(B\)看做汇点,先不考虑额外情况 显然,这是一种两者选其一的问题,我们选择一部分边割去,使这部分边的贡献最小,就是求最小割,我们求出了收 ...
- 又一个js乱码的秘密alert放在js文件里中文乱码,可是放在HTML里显示中文就很好
用文本文档打开你的js文件,文件-另存为,编码更改为UTF-8保存. 回复 | PFly | 园豆:94 (初学一级) | 2017-07-17 21:32 显示结果中文乱码 支持(0)反对(0)回复 ...
- vue从零开始(二)指令
一.v-text和v-html <span v-text="msg"></span> <div v-html="html"> ...
- 2647673 - HANA Installation Failure with signal 11 core dumped
Symptom HANA 2.0 SPS03 installation using hdblcmgui failed due to the below error message. [Error] / ...
- c# 将两个表的有效数据合到一个表中
<asp:DropDownList ID="ddlSpecialty" runat="server" > </asp:DropDownList ...
- git 列出两个分支 或者两个提交版本之间不同的文件名字
只列出名字 git diff remotes/origin/dev remotes/origin/master --name-only
- 8 个 Python 实用脚本,赶紧收藏备用!
脚本写的好,下班下得早!程序员的日常工作除了编写程序代码,还不可避免地需要处理相关的测试和验证工作. 例如,访问某个网站一直不通,需要确定此地址是否可访问,服务器返回什么,进而确定问题在于什么.完成这 ...
- Linux命令——pidof
参考:Linux pidof Command Examples To Find PID of A Program/Command Linux pidof Command Tutorial for Be ...
- 团队最后一次——冲刺+Beta发布
这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/2019autumnsystemanalysisanddesign/ 这个作业要求在哪里 https:// ...