不知道有没有人讨论过……昨天没事干,写了个程序测试DELPHI和BCB的运行速度,结果让我很是诧异。由于一般的程序里字符串操作最多,同时字符串操作也是最耗费时间的,所以我只测试了字符串操作的速度:
测试平台:
DELPHI 6.0 BCB 6.0 gcc 3.3,全部缺省编译选项
赛杨366,128M
测试类型:
DELPHI - shortstring
DELPHI - AnsiString
C++Builder - AnsiString
C++Builder - string(STL)
gcc - STL测试程序:
var
s :string; //缺省是AnsiString,可以修改为shortString
i,j :integer;
begin
for i:=0 to 10000 do
begin
s := '';
for j:=0 to 200 do
s := s + 'a';
end;
end;void main()
{
string s; //对于BCB,可以修改为 AnsiString
for (int i=0; i<10000; i++)
{
s = "";
for (int j=0; j<200; j++)
s = s + "a";
}
}
我原来认为,DELPHI和BCB的AnsiString的操作原理应该是类似的,所以速度应该比较接近。shortstring由于只能小于255字节,把字符串的长度保存在第0位,速度应该会比AnsiString快一些。但是……DELPHI - shortstring 2.** (s)
DELPHI - AnsiString 0.6*
C++Builder - AnsiString 9.**
C++Builder - string(STL) 20.**
gcc - STL 5.**DELPHI 的字符串操作是如此之快???大家能不能讨论一下,或者有条件也帮我测试一下,包括各个版本,VC等等
测试平台:
DELPHI 6.0 BCB 6.0 gcc 3.3,全部缺省编译选项
赛杨366,128M
测试类型:
DELPHI - shortstring
DELPHI - AnsiString
C++Builder - AnsiString
C++Builder - string(STL)
gcc - STL测试程序:
var
s :string; //缺省是AnsiString,可以修改为shortString
i,j :integer;
begin
for i:=0 to 10000 do
begin
s := '';
for j:=0 to 200 do
s := s + 'a';
end;
end;void main()
{
string s; //对于BCB,可以修改为 AnsiString
for (int i=0; i<10000; i++)
{
s = "";
for (int j=0; j<200; j++)
s = s + "a";
}
}
我原来认为,DELPHI和BCB的AnsiString的操作原理应该是类似的,所以速度应该比较接近。shortstring由于只能小于255字节,把字符串的长度保存在第0位,速度应该会比AnsiString快一些。但是……DELPHI - shortstring 2.** (s)
DELPHI - AnsiString 0.6*
C++Builder - AnsiString 9.**
C++Builder - string(STL) 20.**
gcc - STL 5.**DELPHI 的字符串操作是如此之快???大家能不能讨论一下,或者有条件也帮我测试一下,包括各个版本,VC等等
s := s + 'a';这样的代码可能在Delphi中不是通过函数调用来实现的,但是在BCB中必须调用两次函数,一个是AnsiString(char)的构造函数,一个是+运算符的重载函数,这个差别可能就大了。Delphi 我不会使用,只是这样猜想的,不知道Delphi的行家能否同意??比较这个+运算应该只是一个方面,还有其它的像Pos,Insert,Delete,SubString等等操作的速度才可能更全面一些吧。
使用s = s + "a"很慢。
使用s += "a"要快的多。
如果拿VC与Delphi进行比较的话又是另一种结果,但这种区别又有一大部分是因为Frame不一样产生!我不会BCB,对C++也不是十分了解,只能肤浅的这么认为!
delphi处理shortstring的s := s + 'a';是将其首先用
_LStrToString转换为AnsiString,操作完了以后在调用
_LStrFromString转换为shortstring
Microsoft OLE DB Provider for SQL Server 错误 '80040e31' 超时已过期 /Expert/reply.asp,行105
注意Str[0]是String的长度,所以嘿嘿TP不支持AnsiString的,TP当然是最快了
var
s :string; {AnsiString,shortString}
i,j :integer;
begin
writeln('Press ENTER to start...');
readln;
writeln('start');
for i:=0 to 10000 do
begin
s := '';
for j:=0 to 200 do
s := s + 'a';
end;
writeln('ok, press ENTER to end.');
readln;
end.这是 TP7 的程序,自我感觉和 Delphi 7 中使用 ShortString 的速度差不多。
这是为什么?
s := s + 'a';
如果将上面的改成
for j:=0 to 200 do
begin
s[j+1] := 'a';
inc(s[0]);
end;
则速度提高了一倍左右!
for j:=0 to 200 do
begin
s[j+1] := 'a';
inc(s[0]);
end;因为这样的话,你的s最好先事先给它留有足够的空间,不然的话,会使得内存出错的!!!
而AnsiString则不需要!
现在手头没有Delphi
可以看看CPU变量!
Delphi中的一个串实际占用空间比串中的可视内容占用的空间要大,这是因为一个串(not empty String!)至少用这个几个部分组成:串的长度、串的引用计数(当引用次数为0时,串的空间就会自动回收,就是为什么D中的串是一种自管理的数据类型了)、串的实际内容。
另外要知道当你写这样的代码时:
S1:='abas';
S2:='bddas';
S3 :=S1+S2;//<----注意这一步,
在D的编译中并没有把S1+S2的内容Copy到S3中,而是把S1和S2串起始地址链到S3中,这样S3并没有被分配内存,所有速度很高;当你对S3进修改时,S3才会真正的Copy一份S1+S2的内容出来--是不是很麻烦呀?但庆幸的是这些都是D帮我们作好了!
如果不信的话可以作如下的实验:
1:
S1:='asdf';
S2:=S1;//<--这个要快!没有分配内存
2:
S1:='asdf';
S2:=Copy(S1,1,4);//<--重新分配了内存
1应该要快!
至于BCB,我不懂,不过我想应该没象Delphi那样作才对(至于为什么,我想可能是BCB要作到兼容VC中的CString吧??!--BCB可以兼容VC的!也比较NB吧?),不然不会慢那么多
BCB中的AnsiString与DELPHI中的AnsiString速度基本相同。不过加时要使用+=操作符,否则速度极慢。STL中的字符串类型效率比DELPHI和BCB中的AnsiString差一些,但还可以接受。C语言中的字符数组在字符串长度比较小时略有优势,但字符串长度大时效率急剧下降。还有其他意见没有?准备结贴了。
StringBuffer sb = null;
long last = System.currentTimeMillis();
for (int i=0;i<10000;i++)
{
sb = new StringBuffer();
for(int j=0; j<200;j++)
{
sb.append('a');
}
}
long now = System.currentTimeMillis();
System.out.println( (double)(now - last) / 1000 + "秒");
}
}0.22秒如果是append "a"的话,
0.521秒
for(int k=0;k<20;k++)
{
System.gc();
StringBuffer sb = null;
long last = System.currentTimeMillis();
for (int i=0;i<10000;i++)
{
sb = new StringBuffer();
for(int j=0; j<200;j++)
{
sb.append('a');
}
}
long now = System.currentTimeMillis();
System.out.println( (double)(now - last) / 1000 + "秒");
}
}
}
'a'
0.21秒
0.181秒
0.2秒
0.19秒
0.201秒
0.19秒
0.19秒
0.201秒
0.19秒
0.2秒
0.181秒
0.2秒
0.19秒
0.19秒
0.19秒
0.19秒
0.2秒
0.191秒
0.19秒
0.19秒"a"
0.52秒
0.531秒
0.511秒
0.521秒
0.48秒
0.521秒
0.491秒
0.521秒
0.521秒
0.51秒
0.541秒
0.511秒
0.521秒
0.521秒
0.49秒
0.491秒
0.501秒
0.501秒
0.51秒
0.531秒
2 楼主,不知道您的时间是怎么得到的?对于时间是否可以有效表示程序耗时,有写说法,
可能出现楼上所说的:
xinghf(xinghf) ( ) 信誉:100 2003-08-15 16:54:00 得分:0
程序中打出的时间没有参考价值
3 请暂时不要揭贴,写程序看看,最晚周一前全部发布结论(我对这个问题也喊感兴趣)。
4 谢谢。
在DEBUG模式下平均是19~20秒。
在RELEASE模式下,关闭优化,执行结果平均是4~5秒。
打开优化(最快速度),2.0X秒。
D1.1G-》1.2G DDR266:512M
*****************************************************************************
WIN2K(SP3)+VC2003下,楼主的代码
在DEBUG模式下平均是19~20秒。
在RELEASE模式下,关闭优化,执行结果平均是4~5秒。
打开优化(最快速度),2.0X秒。
如果把 s = s+"a"改成 s += "a",
DEBUG下,执行耗时2.46~2.50秒。
RELEASE下如果关闭最优化,执行耗时0.406~0.421秒。如果把 s+="a",改成s.append("s"),
DEBUG下,执行耗时2.39~2.46秒。
RELEASE下关闭最优化0.109或梢高些如果是打开最优化(最大速度),上面两种情况执行时间是0.093~0.125秒。0.109秒出现最频繁。
*******************************************************************************
*******************************************************************************WIN2K(SP3)+BCB6(SP4)下:
原始代码在DEBUG下的执行时间为12秒(虽然比VC2003快,但因为DEBUG下有很多为DEBUG做的工作,没什么意义)。
在RELEASE不做任何优化执行时间为9秒(比VC2003慢,VC2003为4~5秒)。
打开优化为3.98秒。(慢)s += "a"
优化情况下,执行时间为0.09~0.109秒
可是我测完优化情况后,再测非优化,居然也是0.09~0.109(0.09很频繁比VC多多)**************************************************************
我认为s = s + "a" 最慢的问题在于,有两个临时对象要产生。第一个由"a"产生为string,以满足 operation + 的需要。第二个是在 operation + 内部 产生,用于返回生成的string.产生了,我估计还要给销毁吧?如果不做任何优化,如此反复,的确拖累执行速度。也有可能第一个临时对象并不产生,好象basic_string的operation +模板函数可以直接处理char*类型。没有STL源码,不能证实。s += "a",s.append("a")情况则没有以上的负担。常不说话,但愿大家可以看懂我在说什么。^_^
******************************************************************************************************************************************************************稍后我把代码贴出来,大家帮着看看,看有什么问题。正在测BCB 与 DELPHI 下的ansistring ,DELPHI shortstring.
DEBUG下,执行耗时2.39~2.46秒。
RELEASE下关闭最优化0.109或梢高些 改成
^^^^^
***********************************************
RELEASE下关闭最优化0.421~0.437秒
C1.1G, SDRAM 192M, WIN2k(SP4), Eclipse 2.1 IDE环境下, s.append('a'), 0.2秒
s.append("a"), 0.45秒
BCB比VC快这么多?不至于吧?
VC:RELEASE下如果关闭最优化,执行耗时0.406~0.421秒BCB:优化情况下,执行时间为0.09~0.109秒我知道BORLAND的编译器很好,但是也没有认为会快到这个地步?
可是我测完优化情况后,再测非优化,居然也是0.09~0.109(0.09很频繁比VC多多)这个结果的产生,大概有下面的原因:1 BCB的编译选项无法与VC相对应,可能影响了结果。2 STL版本不同。VC用的是 PJ 版,BCB6默认是SGI版,导致结果差异。 ****************************************************************************
BCB 下非优化 s = s + "a",数据应该是3.9X秒。(比VC慢)。还有,在两个编译器都打开最优化的情况下(代码也用最优 s += "a"),BCB似乎比VC稍快点(BCB 0.09~0.109秒,VC 0.109~0.125秒)。大概是因为STL版本的影响?其实这么小的差距也说不了什么问题了。*******************************************************************************一个数据说明不了哪个编译器更好,VC2002的时候,就有人说它是最快的C/C++编译器了——无论编译速度还是产生代码速度(比当时的GCC3.0也快)(资料来源是2002的某期《程序员》)。在Borland 出的书里面(《DDG5》,《DDG6》),也承认VC产生的代码执行效率在主流编译器里面是更快的。BCB和DELPHI有共用一个后台编译器,应该是VC比BCB快。****************************************************************************稍后测测BCB下的ansistring,STL string 的比较。还有DELPHI下的ansistring,shortstring,在看看什么结果吧......
s +="a"DEBUG和RELEASE下结果居然一样?事实上,感觉上面的差距也很小,几乎可以忽略了。
*********************************************************************************
昨天楼主的疑问我又想了想,觉得可能是在BCB下,如果选RELEASE,则包括了优化选项,即使在优化单选框中点none。所以,VC的结果是非优化的,而BCB是优化的,双方的差距看起来很大(这点可以从BCB的优化和非优化执行结果一样得到证实)。而VC在优化后,两者的差距就可以忽略了。还有,我的算法代码都放在一个线程里面,用GetThreadTimes API 来计算时间。DELPHI的代码改了一点(周末休息,琐事很多),大概今晚或明白有结果。
http://expert.csdn.net/Expert/topic/2155/2155456.xml?temp=.881222
我上面的测试结果,s+="a" 要快的多。
s += "a" 1.10-1.14秒,DEBUG和RELEASE优化后的结果都是这样,差别不大,比STL string版优化后慢了一个数量级?反复测试都这个结果.上次忘了出BCB STL string的 s+="a"DEBUG数据,1.12-1.14秒.组合太多了,自己都给搞蒙了.楼主:我在写delphi下的代码的时候,要用一个WIN API Int64ShllMod32,但不知道它在DELPHI 的什么单元定义......
但是看这几个函数的作用,应该可以直接使用 shr (shl) 、mod之类操作符吧?
SysUtils,
windows,
types;var
hThread:tHANDLE;
threadId:cardinal;function convert(use:_FILETIME):int64;
begin
Result := use.dwHighDateTime shl 32 or use.dwLowDateTime;
end;function ThreadFun():integer;stdcall;
var
dummy,ftUserStart,ftUserEnd:_FILETIME;
i,j:integer;
s:ansistring;
qwUserTimeElapsed:int64;
begin
GetThreadTimes(GetCurrentThread(),dummy,dummy,dummy,ftUserStart);
for i:=0 to 10000 do
begin
s := '';
for j := 0 to 200 do // Iterate
begin
s := s + 'a';
end; // for
end;
GetThreadTimes(GetCurrentThread(),dummy,dummy,dummy,ftUserEnd);
qwUserTimeElapsed := convert(ftUserEnd) - convert(ftUserStart);
writeln(qwusertimeelapsed);
ExitThread(0);
result := 0;
end;begin
{ TODO -oUser -cConsole Main : Insert code here } hThread:=createthread(nil,1000,@ThreadFun ,nil,0,threadId);
WaitForSingleObject(hThread,1000);
Sleep(5000);
end.//以上是我在DELPHI下的代码,业余水平,大家见笑。//---------------------------------------------------------------------------
#include <windows.h>
#include <process.h>
#include <iostream>
#include <tchar.h>#include "stdio.h"
#include "conio.h"// TODO: reference additional headers your program requires here
//#include <string>
//using std::string;
#include <vcl.h>
#pragma hdrstop//---------------------------------------------------------------------------
__int64 FileTimeToQuadword(PFILETIME pft)
{
return (Int64ShllMod32(pft->dwHighDateTime,32)|pft->dwLowDateTime);
}
unsigned __stdcall ThreadFunc( void* pArguments )
{
FILETIME ftKernelTimeStart,ftKernelTimeEnd;
FILETIME ftUserTimeStart, ftUserTimeEnd;
FILETIME ftDummy; __int64 qwKernelTimerElapsed,qwUserTimeElapsed,qwTotaltimeElapsed; GetThreadTimes(GetCurrentThread(),&ftDummy,&ftDummy,
&ftKernelTimeStart,&ftUserTimeStart);
AnsiString s; //对于BCB,可以修改为 AnsiString for (int i=0; i<10000; i++)
{
s = "";
for (int j=0; j<200; j++)
// s = s + "a";
s += "a";
// s.append("a");
}
GetThreadTimes(GetCurrentThread(),&ftDummy,&ftDummy,
&ftKernelTimeEnd,&ftUserTimeEnd); qwUserTimeElapsed = FileTimeToQuadword(&ftUserTimeEnd)-FileTimeToQuadword(&ftUserTimeStart);
printf("hello\n");
//qwUserTimeElapsed/=10000000;
printf("%d\n",qwUserTimeElapsed);
_endthreadex(0);
return 0;
}
#pragma argsused
int main(int argc, char* argv[])
{
HANDLE hThread;
unsigned threadID; hThread = (HANDLE)_beginthreadex( NULL, 0, &ThreadFunc, NULL, 0, &threadID );
WaitForSingleObject( hThread, INFINITE ); //Sleep(1000);
//cout << qwUserTimeElapsed << endl; printf("hi\n");
getch();
return 0;
}
//---------------------------------------------------------------------------
以上是我在BCB下的代码,要根据不同的类型在原码基础上修改吧,VC下也是大同小异。但愿没什么逻辑漏洞......业余初学,大家见笑。
http://expert.csdn.net/Expert/topic/1975/1975880.xml?temp=.8823664
如何知道Delphi如何操作字符串
用Delphi写一个例题程序。
用调试软件,动态更踪。更踪到了汇编以后,看懂了那个函数就知道他是如何操作字符串的了。
或者,静态返汇编,看也可以。
[Delphi]
s:=s+'a';//s:string;编译如下
lea eax,[ebp-$04]
mov edx,$0044d9a8
call @LStrCats:=s+'a';//s:shortstring;编译如下
lea eax,[ebp-$0000014]
mov edx,edi
call @LStrFromString
lea eax,[ebp-$0000014]
mov edx,$0044d9e0
call @LStrCat
lea eax,[ebp-$0000014]
mov edx,$000000ff
call @LstrToString
[CString strHello]
36: strHello=strHello+'a';
0040144D push 61h
0040144F lea edx,[strHello]
00401452 push edx
00401453 lea eax,[ebp-18h]
00401456 push eax
00401457 call operator+ (00401044)
0040145C mov dword ptr [ebp-1Ch],eax
0040145F mov ecx,dword ptr [ebp-1Ch]
00401462 mov dword ptr [ebp-20h],ecx
00401465 mov byte ptr [ebp-4],1
00401469 mov edx,dword ptr [ebp-20h]
0040146C push edx
0040146D lea ecx,[strHello]
00401470 call CString::operator= (0040104a)
00401475 mov byte ptr [ebp-4],0
00401479 lea ecx,[ebp-18h]
0040147C call CString::~CString (0040151c)37: strHello+='a';
00401481 push 61h
00401483 lea ecx,[strHello]
00401486 call CString::operator+= (00401528)
[CString strHello]
38: strHello=strHello+"a";
0040148B push offset string "a" (0041401c)
00401490 lea eax,[strHello]
00401493 push eax
00401494 lea ecx,[ebp-1Ch]
00401497 push ecx
00401498 call operator+ (004015c4)
0040149D mov dword ptr [ebp-28h],eax
004014A0 mov edx,dword ptr [ebp-28h]
004014A3 mov dword ptr [ebp-2Ch],edx
004014A6 mov byte ptr [ebp-4],2
004014AA mov eax,dword ptr [ebp-2Ch]
004014AD push eax
004014AE lea ecx,[strHello]
004014B1 call CString::operator= (004015d6)
004014B6 mov byte ptr [ebp-4],0
004014BA lea ecx,[ebp-1Ch]
004014BD call CString::~CString (004015d0)39: strHello+="a";
004014C2 push offset string "a" (0041401c)
004014C7 lea ecx,[strHello]
004014CA call CString::operator+= (004015be)
2 有关类和过程的原码大家都可以在delphi和vc中查得到,这里不贴了