哨兵节点
1、概述
今天和同事一起调代码,定位到一处很耗时的地方,在某个线程中,同步周期需要保证在2ms(如果耗时不到2ms,那么让剩下的时间进行sleep).
但是在调用一个模块的内部函数时,时不时的就飘到了3~5ms,时间抖动毫无保证。后来仔细分析了一下被调用的函数,发现是在查找链表中某个目标节点时,由于目标节点的不确定行,导致耗时飘来飘去。
后来想到是否可以用“哨兵”的思路来解决问题,于是就试了一下,果然有效。特分享于此,使用2段代码来看一下代码执行效率的提升。
2、普通的算法
所谓哨兵,就是一个标志,一个与查找目标对象一样的操作对象。
假如有1000000个纸箱,每个箱子里面有一个纸条,里面写有1~1000000这些数字,数字不会重复。现在别人给一个随机的数字,我们需要从这1000000个箱子里找到与这个数字相同的纸条,找到之后退出操作。
分析:纸箱是无序的,所以我们需要从头遍历
(1)代码1
我们给一个500000的数字,要在这1000000个箱子中寻找纸条数字为500000
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#define LOOP_NUM 1000000
int main(void)
{
long data[LOOP_NUM];
long rand_num = 500000;
struct timeval tv1, tv2;
for (long i = 0;i < LOOP_NUM;i++)
{
data[i] = i;
}
gettimeofday(&tv1,0);
for (long i= 0;i<LOOP_NUM;i++)
{
if (data[i] == rand_num)
{
printf("find the box %ld\n",data[i]);
break;
}
}
gettimeofday(&tv2, 0);
long us1 = tv1.tv_sec * 1000000 + tv1.tv_usec;
long us2 = tv2.tv_sec * 1000000 + tv2.tv_usec;
printf("time elapse %ld\n",us2-us1);
return 0;
}
我们使用for循环遍历所有的箱子查找,我们可以看到查找花了2840us.
(2)代码2(哨兵节点)
int main(void)
{
long data[LOOP_NUM+1];
long rand_num = 500000,i=0;
struct timeval tv1, tv2;
for (long i = 0;i < LOOP_NUM;i++)
{
data[i] = i;
}
data[LOOP_NUM] = 500000; /*增加一个哨兵节点*/
gettimeofday(&tv1,0);
while(1)
{
if(data[i] == rand_num)
{
printf("find the box %ld\n",data[i]);
if(i==LOOP_NUM)
{
printf("find the sentinal box\b");
}
break;
}
i++;
}
gettimeofday(&tv2, 0);
long us1 = tv1.tv_sec * 1000000 + tv1.tv_usec;
long us2 = tv2.tv_sec * 1000000 + tv2.tv_usec;
printf("time elapse %ldus.\n",us2-us1);
return 0;
}
执行结果:
使用哨兵后,很明显提高了代码执行效率,代码1中使用for循环中对于i的最大值每个循环都要进行比较判断,这就降低了代码的执行效率,代码2加入了哨兵节点,多一个纸箱,纸箱里面的纸条写成500000。如果一直查找到哨兵节点才退出循环,表示没有找到。代码2中我们使用while循环,没有了每次箱子最大数量的比较判断,这就增加了代码的执行效率。