【发布时间】:2018-11-01 22:11:14
【问题描述】:
我必须加快在数组中搜索 MAC 地址(大小:32k)。我想从中获得更好的性能,我写了一个小示例代码来显示问题(请注意,数组中的 MAC 将是随机数(随机端口,随机 vlan)并且不是很好地排序(如显示在示例代码)。 现在我正在寻找如何改进的建议,即加快速度:
#include <stdio.h>
#include <string.h>
#define MAX_MAC 32768
typedef unsigned char l2_mac_t[6];
typedef struct l2_s {
int prt;
int vln;
l2_mac_t mac;
}l2_t;
int find_mac(int port, int vlan, l2_mac_t mac);
void fill_mac(void);
static l2_t arr[MAX_MAC] = {0};
int main (void) {
int i = 0;
int res = 0;
fill_mac();
for (i=0;i<MAX_MAC;i++) {
res = find_mac(arr[i].prt,arr[i].vln,arr[i].mac);
if (res%1000 == 0 )
printf("Got MAC %d\n",res);
}
}
int find_mac(int port, int vlan, l2_mac_t mac) {
int i = 0;
for (int i = 0;i< MAX_MAC; i++) {
if (arr[i].prt == port) {
if (arr[i].vln == vlan) {
if (memcmp(arr[i].mac,mac,sizeof(l2_mac_t)) == 0 ) {
//found
return i;
}
}
}
}
}
void fill_mac(void) {
int i = 0;
for (i=0;i<MAX_MAC; i++) {
arr[i].prt = 4;
arr[i].vln = 10;
arr[i].mac[5] = i%255;
arr[i].mac[4] = i%65025;
}
}
下面是获取一些cmets后的一些编辑代码:
好的,
我打算使用哈希并想出了以下内容(这给了我一个段错误,因为它不想在init() 中分配这么多的内存)。另外,这感觉有点像用大锤敲它,肯定有比下面MacSum()更好的哈希方法,欢迎任何建议!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_MAC 32768
#define MacSum(x) (x)[0]*(2^24) \
+(x)[1]*(2^20) \
+(x)[2]*(2^16) \
+(x)[3]*(2^12)\
+(x)[4]*(2^8)\
+(x)[5]
typedef unsigned char l2_mac_t[6];
typedef struct l2_s {
int prt;
int vln;
l2_mac_t mac;
}l2_t;
static unsigned short *L2Hash=0;
int find_mac(int port, int vlan, l2_mac_t mac);
void fill_mac(void);
void init(void);
static l2_t arr[MAX_MAC] = {0};
int main (void) {
int i = 0;
int res = 0;
init();
fill_mac();
for (i=0;i<MAX_MAC;i++) {
res = find_mac(arr[i].prt,arr[i].vln,arr[i].mac);
/*if (res%1000 == 0 )
printf("Got MAC %d\n",res);*/
}
}
int find_mac(int port, int vlan, l2_mac_t mac) {
int i = 0;
int key = 0;
key = MacSum(mac);
if (memcmp(arr[key].mac,mac,sizeof(l2_mac_t)) == 0 ) {
return key;
} else {
for (int i = 0;i< MAX_MAC; i++) {
if (arr[i].prt == port) {
if (arr[i].vln == vlan) {
if (memcmp(arr[i].mac,mac,sizeof(l2_mac_t)) == 0 ) {
return i;
}
}
}
}
}
}
void fill_mac(void) {
int i = 0;
int key = 0;
for (i=0;i<MAX_MAC; i++) {
arr[i].prt = 4;
arr[i].vln = 10;
arr[i].mac[5] = i%255;
arr[i].mac[4] = i%65025;
key = MacSum(arr[i].mac);
L2Hash[key] = i;
}
}
void init(void) {
static int init = 0;
if (init)
return;
L2Hash = (unsigned short*) malloc(0xffffffffffff*sizeof(unsigned short));
}
如需进一步更新问题,请向下滚动至第二个答案
【问题讨论】:
-
保持数组排序并使用二分搜索
-
只要数据结构是一个随机排列的数组,在找到匹配之前,你不能比线性搜索更好。如果您可以将数据结构更改为其他内容,那么您可以做得更好。
-
哈希图、跳过列表、二叉搜索树、sqlite 数据库等。可能性无穷无尽,取决于您需要和可以使用的内容(例如,内存、磁盘空间是否有限制,使用具有某些许可证的外部库)。但即使只是为了保持数组排序,也要考虑插入与查找相比的频率。对于单个查找,您可能必须遍历整个未排序的数组(实际上,如果没有匹配项,您总是必须这样做),而二进制搜索只需要一些比较,并且插入是二进制搜索 + 批量复制 + 可能重新分配。
-
好吧,对最大插槽一半的单个
memmove进行基准测试,看看需要多少次遍历数组来抵消该成本,然后考虑插入频率 (memmove) 与频率查找次数以及查找没有结果的常见情况(= 最坏情况)。 -
另外,您的查询是随机的还是它们是否有关于先前查询的模式(例如,如果可能再次查询相同的条目,您可以缓存或移动它)或插入(例如,如果更有可能查询最新/最旧条目,请相应地更改搜索方向)。但也可以考虑实现一个简单的哈希映射。