不知道有没有人讨论过……昨天没事干,写了个程序测试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等等

解决方案 »

  1.   

    BCB区讨论贴在http://expert.csdn.net/Expert/topic/2135/2135547.xml?temp=.1493189
      

  2.   

    我想Delphi和BCB的String还是有很大区别的,在Delphi中String是一个编译器支持的内部变量类型,本身Pascal就支持String类型,而在C++ Builder中的AnsiString是使用类来实现的,像
    s := s + 'a';这样的代码可能在Delphi中不是通过函数调用来实现的,但是在BCB中必须调用两次函数,一个是AnsiString(char)的构造函数,一个是+运算符的重载函数,这个差别可能就大了。Delphi 我不会使用,只是这样猜想的,不知道Delphi的行家能否同意??比较这个+运算应该只是一个方面,还有其它的像Pos,Insert,Delete,SubString等等操作的速度才可能更全面一些吧。
      

  3.   

    找到部分原因:
    使用s = s + "a"很慢。
    使用s += "a"要快的多。
      

  4.   

    我也只能愚蠢的认为,Delphi的VCL对Pascal的支持要好于C++,编译速度也有了区别。
    如果拿VC与Delphi进行比较的话又是另一种结果,但这种区别又有一大部分是因为Frame不一样产生!我不会BCB,对C++也不是十分了解,只能肤浅的这么认为!
      

  5.   

    shortstring没有AnsiString快的原因是:
    delphi处理shortstring的s := s + 'a';是将其首先用
    _LStrToString转换为AnsiString,操作完了以后在调用
    _LStrFromString转换为shortstring
    Microsoft OLE DB Provider for SQL Server 错误 '80040e31' 超时已过期 /Expert/reply.asp,行105
      

  6.   

    String操作是Delphi的强项来的,Delphi的String不是以Null结尾的,
    注意Str[0]是String的长度,所以嘿嘿TP不支持AnsiString的,TP当然是最快了
      

  7.   

    program TestStr;
    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 的速度差不多。
    这是为什么?
      

  8.   

    for j:=0 to 200 do
          s := s + 'a';
    如果将上面的改成
        for j:=0 to 200 do
        begin
          s[j+1] := 'a';
          inc(s[0]);
        end;
    则速度提高了一倍左右!
      

  9.   

    楼上的朋友,最好不要这么玩如果将上面的改成
        for j:=0 to 200 do
        begin
          s[j+1] := 'a';
          inc(s[0]);
        end;因为这样的话,你的s最好先事先给它留有足够的空间,不然的话,会使得内存出错的!!!
      

  10.   

    也许,ShortString需要复制
    而AnsiString则不需要!
    现在手头没有Delphi
    可以看看CPU变量!
      

  11.   

    我认为Delphi中的串不能简单的看成一个变量类型了,而是一个对象
    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吧?),不然不会慢那么多
      

  12.   

    同意ly_liuyang(Liu Yang)和 blazingfire(烈焰)(正在思考的流浪汉...) ,在Delphi中string类型采用了引用计数的方式来存取字符串变量的值,而string类型的第一个字节是它的长度,这样进行字符串运算时,不需要扫描全部字符,速度当然快了。
      

  13.   

    http://expert.csdn.net/Expert/topic/2139/2139709.xml?temp=.9260523各位有兴趣的话顺便也帮我做做这个比较!
      

  14.   

    总结:
    BCB中的AnsiString与DELPHI中的AnsiString速度基本相同。不过加时要使用+=操作符,否则速度极慢。STL中的字符串类型效率比DELPHI和BCB中的AnsiString差一些,但还可以接受。C语言中的字符数组在字符串长度比较小时略有优势,但字符串长度大时效率急剧下降。还有其他意见没有?准备结贴了。
      

  15.   

    hjmaAsC(继续补丁),不好意思,忘了加上了,这里定义的 s 是 ShortString,它是静态的,不需要事先手动申请。
      

  16.   

    严重同意blazingfire(烈焰)(正在思考的流浪汉...)
      

  17.   

    Java CIII 1.1GHz, 192M, Eclipse 2.1 IDE环境public class Test { public static void main(String[] args) {
    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秒
      

  18.   

    public class Test { public static void main(String[] args) {
    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秒
      

  19.   

    抛开integer等基本数据类型不说,C++B 用的控件都是是Delphi的VCL封装的,肯定比delphi慢
      

  20.   

    1 我不灌水,我还想讨论这个问题。
    2 楼主,不知道您的时间是怎么得到的?对于时间是否可以有效表示程序耗时,有写说法,
      可能出现楼上所说的:
       xinghf(xinghf) ( ) 信誉:100  2003-08-15 16:54:00  得分:0 
     
     
      程序中打出的时间没有参考价值
    3 请暂时不要揭贴,写程序看看,最晚周一前全部发布结论(我对这个问题也喊感兴趣)。
    4 谢谢。  
      

  21.   

    WIN2K+VC2003下,楼主的代码
      在DEBUG模式下平均是19~20秒。
      在RELEASE模式下,关闭优化,执行结果平均是4~5秒。
      打开优化(最快速度),2.0X秒。
      

  22.   

    我的平台是:
    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.
      

  23.   

    如果把 s+="a",改成s.append("s"),
    DEBUG下,执行耗时2.39~2.46秒。
    RELEASE下关闭最优化0.109或梢高些     改成
                       ^^^^^
    ***********************************************
    RELEASE下关闭最优化0.421~0.437秒
      

  24.   

    看来Java和.net的速度有得比啊,只要不犯了字符串大量直接相加的大忌。(用StringBuffer.Append()而不用String1 += String2)D1.1G-》1.2G DDR266:512M , WIN2K(SP3)+VC2003下,s.append("s"),0.421~0.437秒
    C1.1G, SDRAM 192M, WIN2k(SP4), Eclipse 2.1 IDE环境下, s.append('a'), 0.2秒
                                                          s.append("a"), 0.45秒
      

  25.   

    楼上兄弟,我用的不是托管C++代码,不过好象没什么问题,.net的jit编译也会作这些工作,不知道是不是?
      

  26.   

    penc(妖兽) :
    BCB比VC快这么多?不至于吧?
    VC:RELEASE下如果关闭最优化,执行耗时0.406~0.421秒BCB:优化情况下,执行时间为0.09~0.109秒我知道BORLAND的编译器很好,但是也没有认为会快到这个地步?
      

  27.   

    s += "a"
    可是我测完优化情况后,再测非优化,居然也是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,在看看什么结果吧......
      

  28.   

    Bcb下AnsiStrings = s + "a" DEBUG:2.10~2.17秒    RELEASE:2.09~2.10秒。
    s +="a"DEBUG和RELEASE下结果居然一样?事实上,感觉上面的差距也很小,几乎可以忽略了。 
    *********************************************************************************
    昨天楼主的疑问我又想了想,觉得可能是在BCB下,如果选RELEASE,则包括了优化选项,即使在优化单选框中点none。所以,VC的结果是非优化的,而BCB是优化的,双方的差距看起来很大(这点可以从BCB的优化和非优化执行结果一样得到证实)。而VC在优化后,两者的差距就可以忽略了。还有,我的算法代码都放在一个线程里面,用GetThreadTimes API 来计算时间。DELPHI的代码改了一点(周末休息,琐事很多),大概今晚或明白有结果。
      

  29.   

    发现一个有趣的帖子,大家快去看啊
    http://expert.csdn.net/Expert/topic/2155/2155456.xml?temp=.881222
      

  30.   

    另外,不要用s = s + "a"测试。
    我上面的测试结果,s+="a" 要快的多。
      

  31.   

    BCBAnsiString下,
    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 的什么单元定义......
      

  32.   

    我也没有查到……
    但是看这几个函数的作用,应该可以直接使用 shr (shl) 、mod之类操作符吧?
      

  33.   

    谢谢。在DELPHI的WIN32 SDK HELP中,可以看到关于这个API的介绍,我计时间用WIN API GetThreadTimes,它的参数里面有一个FILETIME(DLEPHI中是_FIELTIME),得到的结果要转化成int64,就需要用到这个API......
      

  34.   

    DELPHI中可以直接对Int64类型做shl,shr操作
      

  35.   

    0.375m,delphi ansistring, shortstring 1.x miao.
      

  36.   

    program Project1;{$APPTYPE CONSOLE}uses
      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下也是大同小异。但愿没什么逻辑漏洞......业余初学,大家见笑。
      

  37.   

    字符串比较的方法
    http://expert.csdn.net/Expert/topic/1975/1975880.xml?temp=.8823664
    如何知道Delphi如何操作字符串
    用Delphi写一个例题程序。
    用调试软件,动态更踪。更踪到了汇编以后,看懂了那个函数就知道他是如何操作字符串的了。
    或者,静态返汇编,看也可以。
      

  38.   

    看看他们在干什么:
    [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
      

  39.   

    [Visual C++]
    [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)
      

  40.   

    [Visual C++]
    [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)
      

  41.   

    1 strHello=strHello+"a";操作多用了一个临时对象,多了一次对象创建/复制/销毁操作
    2 有关类和过程的原码大家都可以在delphi和vc中查得到,这里不贴了