随笔-10  评论-36  文章-6  trackbacks-0
    现在计算机的硬件设备的性能增长速度异常迅猛,使得越来越多的程序员开始不再关注代码的执行效率,不再花费心思去构想精妙的算法,优化自己的代码,导致设计的系统越来越庞大、越来越复杂,性能却越来越差,程序员自己也逐渐沦落为蓝领技术工人。一个经过简单编码培训的人就可以胜任程序员的工作吗?我认为不是这样的。一个合格的程序员,除熟练掌握多种编程语言外,创造力才是程序员生命的源泉。而创造力并非天生的,需要丰富的经验加勤奋的思考。本文并非想探讨程序员的成长,只是将此作为引子,希望各位同仁能关注自己编写代码并能为之自豪,并以一个简单的例子说明关注代码优化问题导致的巨大性能提升。即使机器再好,一个编写不良的代码,依然难以达到理想的性能。
    今天测试人员向我抱怨,说我们提交的API代码性能比较差,解析一个90万笔业务的报文居然用了9个小时,这当然是不能接受的。我自己简单测试下,发现在我的T43/1.5G机器上,API的解析速度只能达到每秒30笔,直观觉得代码应存在性能问题。我仔细查阅了程序,没有发现明显的问题。到底是什么导致性能损失的呢?我逐步跟踪每步代码的执行,终于找到了问题所在,简单地讲此性能问题是频繁调用函数strlen()导致的。各位可能非常惊讶,我当时也很惊讶,但情况确实如此。90万笔业务的报文长度约50M,解析报文时我们调用了自己编写的底层代码StrStrExt()替换系统的strstr()以便支持的GB18030汉字,而性能正是StrStrExt()底层函数导致的。
    先看看原始的StrStrExt()函数的代码:
// 查找含汉字串的位置
char* StrStrExt(LPCSTR sSearch,LPCSTR sFind)
{
    
if (IsEmptyStr(sSearch)) return NULL;
    
if (IsEmptyStr(sFind)) return (char*)sSearch;
    ULONG nOffset 
=0;
    ULONG nIndex  
=0;
    ULONG nMaxLen 
= strlen(sSearch);
    ULONG nLen 
= strlen(sFind);
    
while(nOffset < nMaxLen)
    {
        
for(nIndex=0; nIndex<nLen; nIndex ++)
        {
            
if(sSearch[nOffset + nIndex] != sFind[nIndex]) break;
        }
        
if(nIndex == nLen) return (char*)(sSearch + nOffset);
        
int n = IsChineseChar(sSearch + nOffset);
        
if(n > 0)
        {
            
// 汉字处理
            nOffset += n;
        }
        
else
        {
            nOffset
++;
        }
    }
    
return NULL;
}
     发现strlen()对大字符串可能导致性能问题后,我将该函数修改如下:
char* StrStrExt(LPCSTR sSearch,LPCSTR sFind)
{
    
if (IsEmptyStr(sSearch)) return NULL;
    
if (IsEmptyStr(sFind)) return (char*)sSearch;
    ULONG nOffset 
=0;
    ULONG nIndex  
=0;
//    ULONG nMaxLen = strlen(sSearch);
    ULONG nLen = strlen(sFind);
//    while(nOffset < nMaxLen)
    while(sSearch[nOffset] != 0)
    {
        
for(nIndex=0; nIndex<nLen; nIndex ++)
        {
            
if(sSearch[nOffset + nIndex] != sFind[nIndex]) break;
        }
        
if(nIndex == nLen) return (char*)(sSearch + nOffset);

        
int n = IsChineseChar(sSearch + nOffset);
        
if(n > 0)
        {
            
// 汉字处理
//            nOffset += n;
            for(int ii=0; ii<n; ii++)
            {
                
++nOffset;
                
if(sSearch[nOffset] == 0break;
            }
        }
        
else
        {
            nOffset
++;
        }
    }
    
return NULL;
}
    新函数与原函数的唯一差别是不再使用strlen()去获取串的结束位置,而是直接通过\0结束符判断串的结束位置。修改后的代码在我T43的机器上,解析速度提高到每秒3000笔的速度,是原代码的近100倍,达到了系统性能指标的要求。
    这个问题提示我们,程序员应时刻关注代码的性能问题,对核心代码编写者更是如此。
posted on 2008-01-06 12:39 飞鹰 阅读(657) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: