设为首页 加入收藏

TOP

13.2 预先计算
2013-10-07 14:06:44 来源: 作者: 【 】 浏览:51
Tags:13.2 预先 计算

13.2  预先计算

预先计算和缓存联系紧密。当缓存某个计算的结果时,需要付出的代价是在对性能有重大影响的关键路径上完成一次计算。如果采用预先计算,那么甚至连这一次计算也可免了。将预先计算放置在影响性能的关键路径之外(例如初始化阶段),就可以避免在性能关键路径上进行代价高昂的计算。

回到Web服务器实现的示例中,Web服务器将相当的时间花费在字符串处理上,如果可以提高字符串处理的速度,那么服务器的性能将得到显著提升。将字符串或字符转换为大写是经常会遇到的字符串处理任务。如果浏览器给服务器发送一个"Accept:"请求报头,服务器必须能识别,而不管报头的字母是大写还是小写,不必对"accept:","AcCePt:"或其他大小写混合的字符串进行区分。(accept报头告诉服务器可以接收的文档类型,例如text/html,image/gif……)

由于函数memcmp(header, "ACCEPT:", 7)区分大小写,因此在调用memcmp()函数前应先将报头字符串转化为大写格式。方法如下:

  1. for (char *p = header; *p ; p++) { //将报头转化为大写格式  
  2.     *p = toupper(*p);  
  3.     }  
  4.  
  5. if (0 == memcmp(header, "ACCEPT:", 7)) {  
  6.     ...  
  7.     } 

在影响性能的关键路径上,反复调用toupper()的代价是无法接受的,即便将其作为内联函数实现,仍将包含如下形式的条件语句:

  1. return (c >='a' && c<='z')   c   
  2. ('a'-'A') : c; 

这是针对ASCII的实现。而针对EBCDIC字符集(EBCDIC字母表的顺序不是不连续的)的实现会更加复杂。

如果希望避免为可能的库函数调用或内联条件语句的开销,可以预先计算出每个可能出现的字符相应的大写值:

  1. void initLookupTable()  
  2. {  
  3.     for (int i = 0; i < 256; i++) {  
  4.         uppercaseTable[i] = toupper(i);  
  5.         }  

由于uppercaseTable在起始阶段完成初始化,所以islower()和toupper()代价是无须考虑的,其性能也就不成问题。

现在只需执行两条指令即可将字符转化为大写格式,这将显著提高字符串操作的效率:

  1. for (char *p = header; *p ; p++) {  
  2.     *p = uppercaseTable[*p];  
  3.     }  
  4.  
  5. if (0 == memcmp(header, "ACCEPT:", 7)) {  
  6.     ...    
  7.     } 

通过这种方式,可以预先计算出在性能关键路径上出现的其他字符处理函数查询表:islower()、isspace()、isdigit()等等。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇13.3 降低灵活性 下一篇13.4 80-20法则:加快常用路径的..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: