一点由字符串匹配引发的思考
2012-11-02 10:36
351 查看
起因是我的Feature太过简单,在项目组的大家还在忙碌不堪时,我已然开始打酱油了。显然,打酱油比干活累,所以我向老大汇报了。于是乎,老大亲自操刀,review我的代码。结局是:很惨!
接下来的日子,就开始了我的漫漫代码改进之路。
感想是,不过是小小的一个字符串匹配的问题,竟然调了这么多调,而且越往下挖,就越发现更多的细节问题,都是原来不曾考虑过的。短短一周多的调试,收获颇多,遂记于此。
最早版本的代码,调试glibc的库函数,strstr(),结果被批得好惨。要求重改,不要调用系统函数。
当初,我们认为strstr()是用最简单的匹配方法,就是从前往后,每次进行一次后移的方法,显然无论怎么写都理应比这个效率高一些。
方法1:用memcmp来代替strstr,测试结果并不理想。老大提供方法2,针对SIP文本协议解析的一种特殊方法。事实上是,对于一段有意义的,人能读懂的文本,这种方法都适用。即,扫描整个文本,每遇到分隔符做一次暂停,总对当前扫描出的word与token进行匹配,可用匹配方法可以调用memcmp()或strcmp(),也可自己实现。结果,对于第二种算法,无论我们如何改进,都达不到直接用strstr()的性能。遂读strstr()代码,发现其实现并不是我们想的那样简单。作者在注释里写到他的这个算法可以打败绝大多数的字符串匹配算法——我/抠鼻——好吧。作为底层函数的效率,GNU的确做得很好,他们追求的就是效率最高化。首先大量的goto引发的阅读困难,各种奇怪的操作,只为了提高一点点的效率,当大量运行的时候,就可以看出他们的好来。但,结果就是不容易读懂。参考网址:http://blog.chinaunix.net/uid-368446-id-2414244.html
总结几点收获,首先要尽可能地进行自动化测试,减少手工的工作。任何多余的操作都有可能引起效率问题,很多时候可以尽可能地用指针的移动对内存区进行操作,减少其余的赋值操作,以免浪费时间,浪费空间。写代码的过程中,边界条件很重要,这是我以前好容易忽略,并引起系统bug的原因之一。
附上最终源代码,此次性能测试到一段落,接下来,老大push大家趁这段比较空闲的时间,共同学习Effective C++,并给每人分配一个章节作为主讲,主要工作是讲解自己学到的内容,需要注意的地方,遇到的问题,并引发大家进行讨论和思考。一个很好的锻炼机会。如果每个release之间的空余时间,都能找一本书进行这样的学习,也是一个不错的选择。
void strstrMethod_2(unsigned char * pBlob, int var_len)
{
if(NULL == pBlob)
return;
reasonHeaderQ850Present_ = 0;
responseCode_ = 0;
char *pQ850 = "Q.850";
char *pCause = "cause";
char *p = (char *)pBlob;
bool q850FindFlag = false;
while(!reasonHeaderQ850Present_ && *p)
{
char *pToken;
if(!q850FindFlag && !(pToken = strstr(p, pQ850)))
return;
q850FindFlag = true;
if(q850FindFlag && !(pToken = strstr(pToken+TokenLenConst, pCause)))
return;
pToken += TokenLenConst;
while(*pToken && ('=' == *pToken || ' ' == *pToken))
++pToken;
if(*pToken && (*pToken < '0' || *pToken > '9'))
{
p = pToken;
q850FindFlag = false;
continue;
}
while(*pToken && *pToken >= '0' && *pToken <= '9')
{
reasonHeaderQ850Present_ = 1;
responseCode_ = responseCode_ * 10 + (*pToken++ - '0');
}
}
return;
}
本来到这里应该就是结束了,这篇文章是前天写的,不过今天又有更新,在两者的基础上继续改进,新代码性能不错:
void wordDelimiter_8(unsigned char * pBlob, int var_len)
{
const int LEN_Q850 = 5;
const int LEN_CAUSE = 5;
const char TOKEN_Q850[LEN_Q850+1] = "Q.850";
const char TOKEN_CAUSE[LEN_CAUSE+1] = "cause";
unsigned char *p = pBlob;
unsigned char *pEnd = pBlob+var_len;
reasonHeaderQ850Present_ = 0;
responseCode_ = 0;
int i = 0;
while (p<pEnd)
{
while(p<pEnd && *p++!=TOKEN_Q850[0])
;
for (i=1; i<LEN_Q850;)
if (*p++==TOKEN_Q850[i])
++i;
else
break;
if (i==LEN_Q850)
{
//++p;
while(p<pEnd && *p++!=TOKEN_CAUSE[0])
; //++p;
for (i=1; i<LEN_CAUSE;)
if (*p++==TOKEN_CAUSE[i])
++i;
else
break;
if (i==LEN_CAUSE)
{
while (p<pEnd && (*p==' ' || *p== '\t' || *p=='='))
++p;
unsigned char * pValue = p;
while (p<pEnd && *p >='0' && *p <= '9')
responseCode_ = (responseCode_ * 10) + (*p++ -'0');
if (p != pValue)
{
reasonHeaderQ850Present_ = 1;
return;
}
}
}
}
//return;
}
来看看用g++加上-O3编译选项之后,出来的测试结果吧:
测试用例如下:
const int TC_LEN = 6;
unsigned char TC_Data[TC_LEN][100000] = {
//1. Q.850 in header (large string)
"Q.850 ;cause=16 ;\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\n",
//2. Q.850 in tail (large string)
"ReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nQ.850 ;cause=16",
//3. Normal Case
" SIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\naaaaaaaaaaaaaaaaaaaaaaaaaaaaa Q.850 ;cause=16 ;text=\"Terminated\"\nQ.850 ;cause=18 SIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\naaaaaaaaaaaaaaaaaaaaaaaaaaaaa SIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\n",
//4. Without Q.850
"ReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReaso
a5dd
nHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\n",
//5. Special case for strstrMode
"Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;cause=200\nQ.850 ;cause=17 ;",
//6. Q.850 with error cause
" SIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\n\nQ.850 ;cause=a SIP ;cause=200\n Q.850 ;cause=17 SIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP SIP ;caudafsdafafdsadsaf832738922737*&%$&(^%^&*(*&^%$%^&*(*&^%^&*&^%$%^&*&^%$%^&*dafsdafafdsadsaf832738922737*&%$&(^%^&*(*&^%$%^&*(*&^%^&"
};
char TC_Desc[TC_LEN][100] =
{
"Q.850 in header (large string)",
"Q.850 in tail (large string)",
"Normal Case",
"Without Q850",
"Special case for strstrMode",
"Q.850 with error cause"
};
将这三个method循环运行10,000,000后计算运行时间,测试结果如下:
Test result
TC StrstrMode DelimiterMode4 DelimiterMode8
--------------------------------------------------------------------------
1 0.27 0.58 0.21 (Q.850 in header (large string))
2 4.04 4.32 3.94 (Q.850 in tail (large string))
3 2.02 2.25 1.90 (Normal Case)
4 5.64 3.80 3.80 (Without Q850)
5 8.10 17.51 3.62 (Special case for strstrMode)
6 2.80 2.78 2.15 (Q.850 with error cause)
--------------------------------------------------------------------------
给力~
接下来的日子,就开始了我的漫漫代码改进之路。
感想是,不过是小小的一个字符串匹配的问题,竟然调了这么多调,而且越往下挖,就越发现更多的细节问题,都是原来不曾考虑过的。短短一周多的调试,收获颇多,遂记于此。
最早版本的代码,调试glibc的库函数,strstr(),结果被批得好惨。要求重改,不要调用系统函数。
当初,我们认为strstr()是用最简单的匹配方法,就是从前往后,每次进行一次后移的方法,显然无论怎么写都理应比这个效率高一些。
方法1:用memcmp来代替strstr,测试结果并不理想。老大提供方法2,针对SIP文本协议解析的一种特殊方法。事实上是,对于一段有意义的,人能读懂的文本,这种方法都适用。即,扫描整个文本,每遇到分隔符做一次暂停,总对当前扫描出的word与token进行匹配,可用匹配方法可以调用memcmp()或strcmp(),也可自己实现。结果,对于第二种算法,无论我们如何改进,都达不到直接用strstr()的性能。遂读strstr()代码,发现其实现并不是我们想的那样简单。作者在注释里写到他的这个算法可以打败绝大多数的字符串匹配算法——我/抠鼻——好吧。作为底层函数的效率,GNU的确做得很好,他们追求的就是效率最高化。首先大量的goto引发的阅读困难,各种奇怪的操作,只为了提高一点点的效率,当大量运行的时候,就可以看出他们的好来。但,结果就是不容易读懂。参考网址:http://blog.chinaunix.net/uid-368446-id-2414244.html
总结几点收获,首先要尽可能地进行自动化测试,减少手工的工作。任何多余的操作都有可能引起效率问题,很多时候可以尽可能地用指针的移动对内存区进行操作,减少其余的赋值操作,以免浪费时间,浪费空间。写代码的过程中,边界条件很重要,这是我以前好容易忽略,并引起系统bug的原因之一。
附上最终源代码,此次性能测试到一段落,接下来,老大push大家趁这段比较空闲的时间,共同学习Effective C++,并给每人分配一个章节作为主讲,主要工作是讲解自己学到的内容,需要注意的地方,遇到的问题,并引发大家进行讨论和思考。一个很好的锻炼机会。如果每个release之间的空余时间,都能找一本书进行这样的学习,也是一个不错的选择。
void strstrMethod_2(unsigned char * pBlob, int var_len)
{
if(NULL == pBlob)
return;
reasonHeaderQ850Present_ = 0;
responseCode_ = 0;
char *pQ850 = "Q.850";
char *pCause = "cause";
char *p = (char *)pBlob;
bool q850FindFlag = false;
while(!reasonHeaderQ850Present_ && *p)
{
char *pToken;
if(!q850FindFlag && !(pToken = strstr(p, pQ850)))
return;
q850FindFlag = true;
if(q850FindFlag && !(pToken = strstr(pToken+TokenLenConst, pCause)))
return;
pToken += TokenLenConst;
while(*pToken && ('=' == *pToken || ' ' == *pToken))
++pToken;
if(*pToken && (*pToken < '0' || *pToken > '9'))
{
p = pToken;
q850FindFlag = false;
continue;
}
while(*pToken && *pToken >= '0' && *pToken <= '9')
{
reasonHeaderQ850Present_ = 1;
responseCode_ = responseCode_ * 10 + (*pToken++ - '0');
}
}
return;
}
void wordDelimiter_4(unsigned char * pBlob, int var_len) { if(NULL == pBlob) return; reasonHeaderQ850Present_ = 0; responseCode_ = 0; char *pQ850Token = "Q.850"; char *pCauseToken = "cause"; char *pToken = pQ850Token; char *pTokenEnd = (char*)pBlob; bool q850FindFlag = false; while (*pTokenEnd) { --pTokenEnd; do if(!*++pTokenEnd) return; while(*pTokenEnd != *pToken); char *pTokenStart = pTokenEnd; while((';'!=*pTokenEnd) && (' '!=*pTokenEnd) && (':'!=*pTokenEnd) && ('='!=*pTokenEnd) && ('\t'!=*pTokenEnd) && ('\n'!=*pTokenEnd))//delimitate ++pTokenEnd; if(pTokenEnd - pTokenStart != TokenLenConst) { ++pTokenEnd; continue; } char tmp_char = *pTokenEnd; *pTokenEnd = '\0'; if(!strcmp(pTokenStart, pToken))//memcmp() is slower than strcmp() { *pTokenEnd = tmp_char; if(!q850FindFlag) { q850FindFlag = true; pToken = pCauseToken; continue; } else { //To get cause value while (*pTokenEnd && ((' '==*pTokenEnd) || ('='==*pTokenEnd) || ('\t'==*pTokenEnd)))//delimitate ++pTokenEnd; if(*pTokenEnd && (*pTokenEnd < '0' || *pTokenEnd > '9')) { q850FindFlag = false; pToken = pQ850Token; continue; } while (*pTokenEnd && *pTokenEnd >='0' && *pTokenEnd <= '9') { reasonHeaderQ850Present_ = 1; responseCode_ = responseCode_ * 10 + (*pTokenEnd++ -'0'); } if(reasonHeaderQ850Present_) return; } }//if(!memcmp(pTokenStart, pToken, TokenLenConst)) *pTokenEnd = tmp_char; }//while return; }
本来到这里应该就是结束了,这篇文章是前天写的,不过今天又有更新,在两者的基础上继续改进,新代码性能不错:
void wordDelimiter_8(unsigned char * pBlob, int var_len)
{
const int LEN_Q850 = 5;
const int LEN_CAUSE = 5;
const char TOKEN_Q850[LEN_Q850+1] = "Q.850";
const char TOKEN_CAUSE[LEN_CAUSE+1] = "cause";
unsigned char *p = pBlob;
unsigned char *pEnd = pBlob+var_len;
reasonHeaderQ850Present_ = 0;
responseCode_ = 0;
int i = 0;
while (p<pEnd)
{
while(p<pEnd && *p++!=TOKEN_Q850[0])
;
for (i=1; i<LEN_Q850;)
if (*p++==TOKEN_Q850[i])
++i;
else
break;
if (i==LEN_Q850)
{
//++p;
while(p<pEnd && *p++!=TOKEN_CAUSE[0])
; //++p;
for (i=1; i<LEN_CAUSE;)
if (*p++==TOKEN_CAUSE[i])
++i;
else
break;
if (i==LEN_CAUSE)
{
while (p<pEnd && (*p==' ' || *p== '\t' || *p=='='))
++p;
unsigned char * pValue = p;
while (p<pEnd && *p >='0' && *p <= '9')
responseCode_ = (responseCode_ * 10) + (*p++ -'0');
if (p != pValue)
{
reasonHeaderQ850Present_ = 1;
return;
}
}
}
}
//return;
}
来看看用g++加上-O3编译选项之后,出来的测试结果吧:
测试用例如下:
const int TC_LEN = 6;
unsigned char TC_Data[TC_LEN][100000] = {
//1. Q.850 in header (large string)
"Q.850 ;cause=16 ;\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\n",
//2. Q.850 in tail (large string)
"ReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nQ.850 ;cause=16",
//3. Normal Case
" SIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\naaaaaaaaaaaaaaaaaaaaaaaaaaaaa Q.850 ;cause=16 ;text=\"Terminated\"\nQ.850 ;cause=18 SIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\naaaaaaaaaaaaaaaaaaaaaaaaaaaaa SIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\n",
//4. Without Q.850
"ReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReaso
a5dd
nHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\nReasonHeader: SIP ;cause=200\n",
//5. Special case for strstrMode
"Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;Q.85x ;cause=200\nQ.850 ;cause=17 ;",
//6. Q.850 with error cause
" SIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\n\nQ.850 ;cause=a SIP ;cause=200\n Q.850 ;cause=17 SIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP ;cause=200\nSIP ;cau\nSIP ;cause=200\nSIP SIP ;caudafsdafafdsadsaf832738922737*&%$&(^%^&*(*&^%$%^&*(*&^%^&*&^%$%^&*&^%$%^&*dafsdafafdsadsaf832738922737*&%$&(^%^&*(*&^%$%^&*(*&^%^&"
};
char TC_Desc[TC_LEN][100] =
{
"Q.850 in header (large string)",
"Q.850 in tail (large string)",
"Normal Case",
"Without Q850",
"Special case for strstrMode",
"Q.850 with error cause"
};
将这三个method循环运行10,000,000后计算运行时间,测试结果如下:
Test result
TC StrstrMode DelimiterMode4 DelimiterMode8
--------------------------------------------------------------------------
1 0.27 0.58 0.21 (Q.850 in header (large string))
2 4.04 4.32 3.94 (Q.850 in tail (large string))
3 2.02 2.25 1.90 (Normal Case)
4 5.64 3.80 3.80 (Without Q850)
5 8.10 17.51 3.62 (Special case for strstrMode)
6 2.80 2.78 2.15 (Q.850 with error cause)
--------------------------------------------------------------------------
给力~
相关文章推荐
- 一个字符引发的思考
- C语言小程序:除去字符串中间不需要的字符(从小引发大思考)
- 由“饿了么”引发的一点思考
- 一道二级C题引发的思考-- c++函数传递指针的本质 与 字符串指针与字符数组的区别
- 由SpringJdbc引发的一点思考
- 大规模字符串匹配处理的一些思考
- 一个问题引发的一点思考
- 由SpringJdbc引发的一点思考
- Asp.net 服务端缓存引发的一点思考
- 字符串匹配代码及思考
- 每天写一点代码----字符串匹配1(KMP算法)
- 每天写一点代码----字符串匹配算法 2 (BM算法)
- 由“竞争”引发的一点思考 -- 读《ZERO TO ONE》
- HDU 3293 由简单排序引发出的一点思考
- 字符常量包含多个字符的一点思考--有疑问
- sunday算法和自己关于字符串匹配的一些思考
- 阅读作业之由讲义引发的一点思考
- 字符常量包含多个字符的一点思考--有疑问
- MySQL-Front 建表引发的一点小思考(数据表格模版)
- spring依赖注入引发的一点思考