把大神的帖子中一部分摘抄出来,结合自己写的位运算代码和循环代码(数组遍历)进行性能测试分析并给出结果。 摘自: 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)的更多相关文章

  1. C++基础-位运算

    昨天笔试遇到一道题,让实现乘法的计算方法,设计方案并优化,后来总结位运算相关知识如下: 在计算机中,数据是以1010的二进制形式存储的,1bytes = 8 bits,bit就是位,所以位运算就是对每 ...

  2. C/C++中的位运算

    位运算     位运算的运算分量只能是整型或字符型数据,位运算把运算对象看作是由二进位组成的位串信息,按位完成指定的运算,得到位串信息的结果. 位运算符有:     &(按位与).|(按位或) ...

  3. P3613 睡觉困难综合征 LCT+贪心+位运算

    \(\color{#0066ff}{ 题目描述 }\) 由乃这个问题越想越迷糊,已经达到了废寝忘食的地步.结果她发现--晚上睡不着了!只能把自己的一个神经元(我们可以抽象成一个树形结构)拿出来,交给D ...

  4. STL+位运算的文件

    1.queue 队列 queue的头文件是<queue>. 定义queue对象的示例代码如: queue<int>q;  队列内存放的是int类型的数 queue<dou ...

  5. 一文了解有趣的位运算(&、|、^、~、>>、<<)

    1.位运算概述 从现代计算机中所有的数据二进制的形式存储在设备中.即0.1两种状态,计算机对二进制数据进行的运算(+.-.*./)都是叫位运算,即将符号位共同参与运算的运算. 口说无凭,举一个简单的例 ...

  6. 位运算(&、|、^、~、>>、<<)

    1.位运算概述 从现代计算机中所有的数据二进制的形式存储在设备中.即0.1两种状态,计算机对二进制数据进行的运算(+.-.*./)都是叫位运算,即将符号位共同参与运算的运算. 口说无凭,举一个简单的例 ...

  7. 原生Redis跨数据中心双向同步优化实践

    一.背景 公司基于业务发展以及战略部署,需要实现在多个数据中心单元化部署,一方面可以实现多数据中心容灾,另外可以提升用户请求访问速度.需要保证多数据中心容灾或者实现用户就近访问的话,需要各个数据中心拥 ...

  8. Angular 1 深度解析:脏数据检查与 angular 性能优化

    TL;DR 脏检查是一种模型到视图的数据映射机制,由 $apply 或 $digest 触发. 脏检查的范围是整个页面,不受区域或组件划分影响 使用尽量简单的绑定表达式提升脏检查执行速度 尽量减少页面 ...

  9. 关于位图数据和标记位-P3

    文章目录 1 背景 1.1 问题 2 问题1探究 2.1 没有区的情况 2.2 一个区的情况 2.3 两个区的情况 2.4 三个区的情况 2.5 四个区的情况 2.6 五个区的情况 3 问题2探究 3 ...

随机推荐

  1. Udp客户端与服务通讯

    使用UDP与服务端通讯时候,同样需要先启用udp服务端监控,当服务端启动成功,在启动客户端 首先UDP服务端类,代码如下: public class UdpServerTest { public vo ...

  2. C# vb .net实现旋转特效滤镜

    在.net中,如何简单快捷地实现Photoshop滤镜组中的旋转特效呢?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第一步 ...

  3. springmvc 注解二

    @SessionAttributes @sessionattributes注解应用到Controller上面,可以将Model中的属性同步到session作用域当中. SessionAttribute ...

  4. 单词eschaunge交易所eschaunge交换

    Exchange of one person or thing for another; reciprocal giving and receiving: (a) of prisoners of wa ...

  5. 精选SpringBoot八大开源项目:支付、秒杀、全文搜索等

    前言 曾在自己的博客中写下这样一段话:有一种力量无人能抵挡,它永不言败生来倔强.有一种理想照亮了迷茫,在那写满荣耀的地方. 如今,虽然没有大理想抱负,但是却有自己的小计划.下面是这一年来,自己利用闲暇 ...

  6. 使用Blynk打造一款物联网产品

    前言 一直以来想自己打造一款物联网产品. 围绕这个话题写过一些文章: 一辆树莓派可编程小车的问题 基于树莓派的积木化编程解决方案 物联网相关开源项目整理 物联网.开源硬件与开源社区 之前在一辆树莓派可 ...

  7. unity shader入门(三)逐像素光照,Blinn-Phong模型

    与上篇逐顶点光照很像,只是改为在片元着色器中计算光照,下为逐像素光照shader Shader "study/Chapter6/PixelShader"{ Properties{ ...

  8. appium自动化webview时遇到的chromedriver问题

    安卓app里面的网页,基本上都是使用手机系统上的webview 去显示的. 安卓 webview 可以看成是 手机上的 chrome 浏览器精简版. appium desktop 里面内置了 用于 w ...

  9. jQuery知识梳理20190818

    目录 jQuery知识梳理20190818 1. 时间绑定和解绑 2. 区别mouseover与mouseenter 3. 时间委托(委派/代理) 4 . 多库共存 5.window.onload与$ ...

  10. MySQL-CentOS7上安装Mysql5.7

    #安装 wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm .noarch.rpm yum instal ...