文章分类
全部分类
文章存档
2007年08月
最新评论
1.天方听书网有声图书领域的技术航母航母航母
2133333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333...
--匿名
2.天方听书网有声图书领域的技术航母航母航母
tst
--匿名
3.动网论坛短消息模块过滤不严格的注入漏洞
不错
--woaishei
4.天方听书网有声图书领域的技术航母航母航母
我来测试一下超长的文字,是否能全部显示?我来测试一下超长的文字,是否能全部显示?我来测试一下超长...
--woaishei
5.天方听书网有声图书领域的技术航母航母航母
枯栽奔要棋霜
--woaishei
6.天方听书网有声图书领域的技术航母航母航母
我来测试一下超长的文字,是否能全部显示?我来测试一下超长的文字,是否能全部显示?我来测试一下超长...
--我是谁?
7.天方听书网有声图书领域的技术航母航母航母
asdfasdf
--asdf
文章
  • 《一次ASP字符串连接“&”优化(从>90s到0.7s) 》 2007-08-25 10:43

       前言:今天公司的老调查系统需要增加一个导出参与用户资料到.txt的功能。最多1个小时的工作,却进行了3个多小时,归其原因:一、公司网速太慢。更新外网数据、测试、等待超过半个小时。二、程序代码未优化。程序执行时间超过90s直至超时(当时只导出了多一半用户,估计完整执行时间会超过180s),被判不合格。最终找到原因在于字符串连接(好古老的问题)并通过优化执行时间降低到0.7s,速度提高100倍。

        项目环境:ASP(VBScript)+MS SQLSERVER 2000+用户数据2600条

       相信很多人都回使用下面的&字符串连接方式。仅列出开始时的主要代码:

    '[读取SQL结果到二维数组 UserInfo 中略]
    '
    UserInfo = 0 ID,1 SV_ID,2 RECORD,3 Province,4 City,5 Name,6 Sex,7 Address,8 PostCode,9 Phone,10 OtherInfo,11 UserName,12 IP,13 DateTime
    Dim OutputText  '输出文本内容
    Dim SurveyInfo '调查基本信息
    '
    .
    For i=0 To UBound(UserInfo,2)
        OutputText 
    = OutputText & VbCrLf & "姓名:" &  UserInfo(5,i) & VbCrLf & _
                            
    "省份:" & UserInfo(3,i) & "     城市:" & UserInfo(4,i) & VbCrLf & _
                            
    "联系地址:" & UserInfo(7,i) & "     邮编:" & UserInfo(8,i) & VbCrLf & _
                            
    "电话:" & UserInfo(9,i) & VbCrLf
        
        
    ' [OtherInfo 用户其他资料特殊资料的处理,与上面相同需要 6次 OutputText连接      代码略]

        OutputText 
    = OutputText & "IP:" & UserInfo(12,i) & "     Time:" &  UserInfo(13,i) & VbCrLf & _ 
                            
    "------------------------------------------------------------" & VbCrLf
    Next


    程序写完后,本机测试通过(仅10个用户资料)。传到外网服务器上执行超时。开始以为什么地方处理的有问题,后来才发现连接字符串这里消耗太多的时间。于是开始寻求解决办法。
    C#、VB6 中都有StringBuilder,ASP中应该如何处理呢?(后来找到MSDN,方知ASP中也可以调用StringBuilder)。通过GOOGLE找到了《改进 ASP 应用程序中的字符串处理性能》-MSDN。于是按照 MSDN中的技巧通过使用() 括号将代码更改成如下:

    '下面仅列出主要代码。[读取SQL结果到二维数组 UserInfo 中略]
    '
    UserInfo = 0 ID,1 SV_ID,2 RECORD,3 Province,4 City,5 Name,6 Sex,7 Address,8 PostCode,9 Phone,10 OtherInfo,11 UserName,12 IP,13 DateTime
    Dim OutputText  '输出文本内容
    Dim SurveyInfo '调查基本信息
    '
    .
    For i=0 To UBound(UserInfo,2)
        OutputText 
    = OutputText & (VbCrLf & "姓名:" &  UserInfo(5,i) & VbCrLf & _
                            
    "省份:" & UserInfo(3,i) & "     城市:" & UserInfo(4,i) & VbCrLf & _
                            
    "联系地址:" & UserInfo(7,i) & "     邮编:" & UserInfo(8,i) & VbCrLf & _
                            
    "电话:" & UserInfo(9,i) & VbCrLf)
        
        
    ' [OtherInfo 用户其他资料特殊资料的处理,与上面相同需要 3次 OutputText连接      代码略]

        OutputText 
    = OutputText & ("IP:" & UserInfo(12,i) & "     Time:" &  UserInfo(13,i) & VbCrLf & _ 
                            
    "------------------------------------------------------------" & VbCrLf)
    Next

     

    运行,优化效果立刻显现出来执行时间 23s。
    为什么增加“()”后就能这么明显的效率?MSDN中的解释是:“通过更改优先顺序,来减小大多数字符串连接操作中处理的字符串大小。”
    “在最初的代码中,ASP 编译器将查看等号右边的表达式,并从左到右进行计算。结果,每次重复都要进行 29 个连接操作,这些操作针对不断增长的 OutputText 进行。在新版本中,我们提示编译器更改操作顺序。现在,它将按从左到右、从括号内到括号外的顺序计算表达式。此技术使得这些操作针对的是不会增长的较小字符串,只有3个是针对不断增长的大的 OutputText。” 。

    图 1:标准连接与加括号连接在内存使用模式方面的比较(来自MSDN中例子)

    微软还给出了使用 StringBuilder 的优化方法。考虑到ASP中需要创建外部对象,而且微软例子中StringBuilder优化法对比“括号”技巧,对性能提高不明显,因此没有尝试使用。(关于 StringBuilder 的性能可以参考 《改进ASP.....》一文)

    23s的速度还是不能接受。根据上面的结果得知降低对大字符串的连接次数,能明显改善性能。因此继续在字符串连接上想办法:

    '下面仅列出主要代码。[读取SQL结果到二维数组 UserInfo 中略]
    '
    UserInfo = 0 ID,1 SV_ID,2 RECORD,3 Province,4 City,5 Name,6 Sex,7 Address,8 PostCode,9 Phone,10 OtherInfo,11 UserName,12 IP,13 DateTime
    Dim OutputText  '输出文本内容
    Dim SurveyInfo '调查基本信息
    Dim TempItemText  '临时中间字符串连接变量(*关键)
    '
    .
    For i=0 To UBound(UserInfo,2)
        TempItemText 
    = TempItemText & (VbCrLf & "姓名:" &  UserInfo(5,i) & VbCrLf & _
                            
    "省份:" & UserInfo(3,i) & "     城市:" & UserInfo(4,i) & VbCrLf & _
                            
    "联系地址:" & UserInfo(7,i) & "     邮编:" & UserInfo(8,i) & VbCrLf & _
                            
    "电话:" & UserInfo(9,i) & VbCrLf)
        
        
    ' [OtherInfo 用户其他资料特殊资料的处理,与上面相同需要 0 次 OutputText连接      代码略]

        TempItemText 
    = TempItemText & ("IP:" & UserInfo(12,i) & "     Time:" &  UserInfo(13,i) & VbCrLf & _ 
                            
    "------------------------------------------------------------" & VbCrLf)
        
    '减少10倍大字符串连接
        If ((i+1Mod 10=0 Then
            OutputText 
    =  OutputText & TempItemText
            TempItemText 
    = ""
        
    End If
    Next
    If TempItemText<>"" Then
        OutputText 
    =  OutputText & TempItemText
    End If

    可以看出代码增加了一个中间变量TempItemText用来连接每个用户资料,直接减少OutputText连接3倍。又通过 i 于 10取余数,大约每10个用户资料连接一次OutputText,再次减少10倍。Next后增加一个代码对最后可能的<10个用户的资料进行次OutputText连接。总共优化15次OutputText连接。

    至此在没有使用StringBuilder的情况下,将程序优化到0.7s,已能满足项目要求。

    总结:一、利用表达式优先级减少对大字符串连接次数。(仅增加一对括号,对原代码的影响很少*推荐)
                二、利用小字符串做中间变量减少对大字符串连接次数。
                三、这个优化方法适用范围不局限在ASP中(C#等)。

    文献参考:《改进 ASP 应用程序中的字符串处理性能

   分类:[默认分类]阅读(395)评论(0)
网友评论
934:    
  发表评论
     
  姓名:
  内容: