同意小雨哥的解释。顺便问一下,你是用什么工具或方法得到ElapsedTime的?因为我也想测一下我程序的性能。
To Beyondbill:
其实string这种数据类型本身很简单,就是一个指针加上它前面的两个32位的管理数据。编译器本身并没有对这种数据类型做多少所谓的“存取优化”,正好相反,由于copy on write机制的存在,它还可能在程序员不知情的情况下降低性能。
而小雨哥所说的“尽可能地一次性分配内存,避免逐次申请,以加快操作”的存取优化技术并不是指编译器本身对这种数据类型提供的,而是程序员“自己”考虑的问题。
以楼主所举的代码二为例--
for I := 1 to bbq do //String
S:=S+bb+#13#10
这是原来没有优化的代码,如果大家稍微注意一下就可以发现:由于在整个字符串循环连接过程中,bb的内容(或者说长度)是不变的,那在循环次数确定的情况下,我们知道最终字符串S的长度其实在循环开始(也就是开始连接字符串)之前就是已经确定了的。因此这段代码可以用预分配字符串长度的方法来优化--
// 优化方案一:
SetLength(S,bbq*(Length(bb)+2));
j:=0;
for i:=1 to bbq do
begin
for k:=1 to Length(bb) do
begin
inc(j);
S[j]:=bb[k]
end;
S[j+1]:=#13;
S[j+2]:=#10;
j:=j+2
end
基本上,代码写成这样的话,string数据类型的性能潜力已经发挥得差不多了。不过,让我们来看看Delphi帮助里面对string数据类型的一段描述,原文我就不给出了,大意是:“如果用索引的方式(即S
:='A')这种方式来写字符串的话,也会引发copy on write机制的作用”。这句话的意思是说,如果有字符串S:='abc'的话,那执行S[1]:='A'赋值语句的时候,会自动生成原字符串'abc'的一个副本。因此为了避开copy on write机制,上面的优化方案一还可以再改一下--
// 优化方案二:
var
S:string;
psChar;
i,j,k:integer;
begin
SetLength(S,bbq*(Length(bb)+2));
ps:=Pointer(S);
j:=0;
for i:=1 to bbq do
begin
for k:=1 to Length(bb) do
begin
ps[j]:=bb[k];
inc(j);
end;
ps[j]:=#13;
ps[j+1]:=#10;
j:=j+2
end
end
请小雨哥和Beyondbill两位测一下,经过这样子优化的程序不论循环次数加大到多少,性能都绝对要比用TStringList要好。