把大神的帖子中一部分摘抄出来,结合自己写的位运算代码和循环代码(数组遍历)进行性能测试分析并给出结果。 摘自: https://www.gameres.com/827195.html
本文适用于所有脏标记遍历功能,提升性能几倍,本文以游戏中玩家的属性同步作为例子进行介绍。
先说性能分析结果:一般玩家属性列表也就120个够用了,其中常用的攻击,防御,血蓝等,不超过20个。每0.5秒同步一次,那么变化的常用属性更少。
当变化10个属性,位运算性能提升6倍,20个时4倍,如图所示:
总结:位运算效率高,并且把常用属性定义为低位效率更高。 其次是数组(原因是遍历),再其次是set(影响原因是hash函数、hash扩容、二叉树节点转换),最差是stl之bitset(原因:本质也是数组)
优化前的循环算法(数组):
1 const int N = 128; 2 class BitSet 3 { 4 public: 5 BitSet() 6 { 7 memset(m_szBits,0,sizeof(m_szBits)); 8 m_bBitsDirty = false; 9 } 10 int Set(size_t i) 11 { 12 if(i >= 0 && i < N) 13 { 14 ++m_szBits[i]; 15 16 m_bBitsDirty = true; 17 18 } 19 return 0; 20 } 21 int Get(size_t i) const 22 { 23 if(i >= 0 && i < N) 24 { 25 return m_szBits[i] > 0; 26 } 27 return 0; 28 } 29 void Clean() 30 { 31 memset(m_szBits,0,sizeof(m_szBits)); 32 m_bBitsDirty = false; 33 } 34 bool IsDirty() const 35 { 36 return m_bBitsDirty; 37 } 38 private: 39 char * m_szBits[N]; 40 bool m_bBitsDirty; 41 };
优化后的位运算:
1 const int nLLLeng = 64; 2 class NewBitSet 3 { 4 public: 5 NewBitSet():llLow(0ull),llHight(0ull) 6 { 7 } 8 void Set(size_t i) 9 { 10 if(i > 0 && i < nLLLeng) 11 { 12 llLow |= 1ull << i; 13 } 14 else if (i < nLLLeng * 2) 15 { 16 llHight |= 1ull << (i & 0x3F); // 0x3F 是64的16进制,这样做是相当于减64 17 } 18 } 19 void GetAllDirty(int * arrDirty, int & nMaxCount) const 20 { 21 unsigned long long nllLowTemp = llLow; 22 unsigned long long nllHightTemp = llHight; 23 nMaxCount = -1; 24 while (nllLowTemp) 25 { 26 arrDirty[++nMaxCount] = __builtin_ffsll(nllLowTemp) - 1; 27 nllLowTemp &= (nllLowTemp - 1); 28 } 29 while (nllHightTemp) 30 { 31 arrDirty[++nMaxCount] = __builtin_ffsll(nllHightTemp) - 1 + nLLLeng; 32 nllHightTemp &= (nllHightTemp - 1); 33 } 34 } 35 void Clean() 36 { 37 llLow = llHight = 0ull; 38 } 39 40 bool IsDirty() const 41 { 42 return llLow || llHight; 43 } 44 private: 45 unsigned long long int llLow; 46 unsigned long long int llHight; 47 };
测试用例:
1 #include <iostream> 2 #include <sys/time.h> 3 #include<stdlib.h> 4 #include <algorithm> 5 #include <math.h> 6 #include <stdio.h> 7 #include<vector> 8 #include<map> 9 #include <string.h> 10 using namespace std; 11 const int N = 128; 12 class BitSet 13 { 14 public: 15 BitSet() 16 { 17 memset(m_szBits,0,sizeof(m_szBits)); 18 m_bBitsDirty = false; 19 } 20 int Set(size_t i) 21 { 22 if(i >= 0 && i < N) 23 { 24 ++m_szBits[i]; 25 26 m_bBitsDirty = true; 27 28 } 29 return 0; 30 } 31 int Get(size_t i) const 32 { 33 if(i >= 0 && i < N) 34 { 35 return m_szBits[i] > 0; 36 } 37 return 0; 38 } 39 void Clean() 40 { 41 memset(m_szBits,0,sizeof(m_szBits)); 42 m_bBitsDirty = false; 43 } 44 bool IsDirty() const 45 { 46 return m_bBitsDirty; 47 } 48 private: 49 char * m_szBits[N]; 50 bool m_bBitsDirty; 51 }; 52 53 54 const int nLLLeng = 64; 55 class NewBitSet 56 { 57 public: 58 NewBitSet():llLow(0ull),llHight(0ull) 59 { 60 } 61 void Set(size_t i) 62 { 63 if(i > 0 && i < nLLLeng) 64 { 65 llLow |= 1ull << i; 66 } 67 else if (i < nLLLeng * 2) 68 { 69 llHight |= 1ull << (i & 0x3F); // 0x3F 是64的16进制,这样做是相当于减64 70 } 71 } 72 void GetAllDirty(int * arrDirty, int & nMaxCount) const 73 { 74 unsigned long long nllLowTemp = llLow; 75 unsigned long long nllHightTemp = llHight; 76 nMaxCount = -1; 77 while (nllLowTemp) 78 { 79 arrDirty[++nMaxCount] = __builtin_ffsll(nllLowTemp) - 1; 80 nllLowTemp &= (nllLowTemp - 1); 81 } 82 while (nllHightTemp) 83 { 84 arrDirty[++nMaxCount] = __builtin_ffsll(nllHightTemp) - 1 + nLLLeng; 85 nllHightTemp &= (nllHightTemp - 1); 86 } 87 } 88 void Clean() 89 { 90 llLow = llHight = 0ull; 91 } 92 93 bool IsDirty() const 94 { 95 return llLow || llHight; 96 } 97 private: 98 unsigned long long int llLow; 99 unsigned long long int llHight; 100 }; 101 102 int nPrintCount = 1; 103 104 void DirtyBit(int nRandCount) 105 { 106 NewBitSet tDirty; 107 int nRand = 0; 108 //srand((unsigned)time(0)); 109 for (int i = 0; i < nRandCount;i++) 110 { 111 // nRand = rand()%126 + 1; 112 tDirty.Set(i+1); 113 } 114 if (!tDirty.IsDirty()) 115 { 116 return; 117 } 118 int arrDirty[nLLLeng * 2] = {0}; 119 //同步自己执行次数 120 int nMaxCount = 0; 121 tDirty.GetAllDirty(arrDirty, nMaxCount); 122 nMaxCount = 0; 123 //同步WS执行次数 124 tDirty.GetAllDirty(arrDirty, nMaxCount); 125 126 int nNotPrint = 0; 127 for (int i = 0; i< nMaxCount; i++) 128 { 129 nNotPrint = arrDirty[i]; 130 } 131 tDirty.Clean(); 132 } 133 134 void DirtyArr(int nRandCount) 135 { 136 BitSet tDirty; 137 int nRand = 0; 138 // srand((unsigned)time(0)); 139 for (int i = 0; i < nRandCount;i++) 140 { 141 // nRand = rand()%126 + 1; 142 tDirty.Set(i+1); 143 } 144 if (tDirty.IsDirty()) 145 { 146 int arrDirty[N] = {0}; 147 int nMaxCount = -1; 148 //同步自己执行次数 149 for (int i = 0; i< N; ++i) 150 { 151 if (tDirty.Get(i)) 152 { 153 arrDirty[++nMaxCount] = i; 154 } 155 } 156 //同步WS执行次数 157 nMaxCount = -1; 158 for (int i = 0; i< N; ++i) 159 { 160 if (tDirty.Get(i)) 161 { 162 arrDirty[++nMaxCount] = i; 163 } 164 } 165 int nNotPrint = 0; 166 for (int i = 0; i< nMaxCount + 1; i++) 167 { 168 nNotPrint = arrDirty[i]; 169 } 170 } 171 172 tDirty.Clean(); 173 } 174 175 int main() 176 { 177 float time_use=0; 178 struct timeval start; 179 struct timeval end; 180 int nTestCount =100 ; 181 gettimeofday(&start,NULL); 182 183 nPrintCount = 1; 184 //处理过程--开始 185 for (int i = 0; i< 10000; ++i) 186 { 187 DirtyBit(nTestCount); 188 } 189 //处理过程--结束 190 191 cout<<endl; 192 gettimeofday(&end,NULL); 193 time_use=(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec);//微秒 194 printf("time_use is %.10f ",time_use); 195 196 nPrintCount = 1; 197 gettimeofday(&start,NULL); 198 //处理过程--开始 199 for (int i = 0; i< 10000; ++i) 200 { 201 DirtyArr(nTestCount); 202 } 203 //处理过程--结束 204 205 cout<<endl; 206 gettimeofday(&end,NULL); 207 208 time_use=(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec);//微秒 209 printf("time_use is %.10f ",time_use); 210 return 0; 211 }