一次ASP字符串连接“&”优化(从>90s到0.7s)

    前言:今天公司的老调查系统需要增加一个导出参与用户资料到.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 应用程序中的字符串处理性能

posted on 2006-03-23 15:27  flower.b  阅读(4978)  评论(4编辑  收藏  举报