玩家属性同步优化-脏数据标记(位运算、数组、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 ...
随机推荐
- 使用Powershell启用/关闭Windows功能
接上一篇博客,依旧是需要制作安装包,需要开启系统的MSMQ功能.这里就用到了dism.exe DISM全称是Deployment Image Servicing and Management(部署映像 ...
- Linux Shell/Bash wildcard通配符、元字符、转义符使用
说到shell通配符(wildcard),大家在使用时候会经常用到.下面是一个实例: 1 1 2 3 4 [chengmo@localhost ~/shell]$ ls a.txt b.txt ...
- Python进阶(四)----生成器、列表推导式、生成器推导式、匿名函数和内置函数
Python进阶(四)----生成器.列表推导式.生成器推导式.匿名函数和内置函数 一丶生成器 本质: 就是迭代器 生成器产生的方式: 1.生成器函数
- mac杂记
brew 安装.更新 https://blog.csdn.net/fxp850899969/article/details/53284193 vmware work 15 pro https://ww ...
- Android常用优秀开源框架整理
前言 AOSF:全称为Android Open Source Framework,即Android优秀开源框架汇总.包含:网络请求okhttp,图片下载glide,数据库greenDAO,链式框架Rx ...
- 缓冲区溢出漏洞 ms04011
DSScan使用 扫描目标主机是否存在ms04011漏洞 getos使用 获取操作系统类型 > getos.exe 192.168.1.101 ------------------------- ...
- Windows上安装ElasticSearch7
安装JDK1.8(包括)以上版本 安装ElasticSearch ElasticSearch下载地址: https://www.elastic.co/downloads/elasticsearch 双 ...
- 【兼容调试】cffi library '_openssl' has no function, constant or global variable named 'Cryptography_HAS
重装cryptography就好了. conda uninstall cryptography conda install cryptography https://github.com/pyca/c ...
- php的微信公众平台开发接口类
<?php define("TOKEN", "weixin"); $wechatObj = new wechatCallbackapiTest(); if ...
- 04-JavaScript的操作
本篇主要介绍获取元素的方法.操作元素.数组和字符串的操作方法.定时器和封闭函数.以及贪吃蛇案例: 一.获取元素的方法 1.document.getElementById:可以使用内置对象documen ...