谁说Delphi没有哈希?--Delphi中,TStringList和THashedStringList的性能对比

    技术2022-05-11  130

    曾经看到很多人在嚷嚷Delphi没有哈希表,这些人的动手意识姑且不论,却还有很多人以此来证明Delphi比别的语言垃圾,实在是...

    好,牢骚打住,转接正题。

    TStringList是我们常用的字符串列表类型,用法就不在这里赘述,但是,在数据其项数增多时,其搜索(主要是name/key搜索和indexof搜索)性能会急剧下降,原因是TStringList的内部存储使用了链表形式,而搜索操作使用了循环遍历方式。

    值得高兴的是,在iniFiles单元,Delphi为我们提供了THashedStringList类型,即,经过哈希处理的TStringList,它继承自TStringList,只是对搜索方法进行了优化,因此,我们完全可以放心的在大量字符串搜索的时候使用它来代替TStringList,而需要改变的只是在:=的后面用THashedStringList.create来代替TStringList.create,但其速度却提高了一个数量级。

    为了显示两者间性能的差距,我写了几个简单的语句来测试他们各自的特性。

     

    unit ufrmMainForm; interface uses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls, StrUtils,IniFiles;type  TForm1  =   class (TForm)    btn1: TButton;    mmo1: TMemo;    procedure btn1Click(Sender: TObject);   private      { Private declarations }    public     procedure testTHashStringList;    procedure testTStringList;     { Public declarations }   end;var  Form1: TForm1;implementationuses DateUtils; {$R *.dfm} procedure TForm1.btn1Click(Sender: TObject);begin    testTStringList;    mmo1.Lines.Add( ' -------------------- ' );    testTHashStringList;end;procedure TForm1.testTHashStringList; var    hsl: THashedStringList;  I: Integer;  datePointer: TDateTime;  hslTime, hslTimeC, hslTimeI: Int64;  tempInt: Integer;  tempstr:  string  ;begin     hslTime : =   0 ;    hslTimeC : =   0 ;    datePointer : =  Now();    hsl : =  THashedStringList.Create();     for  I : =   1  to  200000   do     begin        hsl.Add( ' string_ ' + IntToStr(i));    end;    hslTime : =  MilliSecondsBetween(Now, datePointer);    mmo1.Lines.Add( ' 200000 项 THashedStringList 创建耗时: ' + IntToStr(hslTime) + ' 毫秒 ' );    datePointer : =  Now();     for  I : =   0  to  200   do     begin        tempInt : =  hsl.IndexOf( ' string_ ' + IntToStr(i * 1000 ));    end;    hslTime : =  MilliSecondsBetween(Now, datePointer);    mmo1.Lines.Add( ' 200 项字符串搜索 THashedStringList 耗时: ' + IntToStr(hslTime) + ' 毫秒 ' );    datePointer : =  Now;     for  I : =   1  to  200000   do     begin        tempstr : =  hsl.Strings[i  - 1 ];    end;    hslTime : =  MilliSecondsBetween(Now, datePointer);    mmo1.Lines.Add( ' 200000 项索引搜索 THashedStringList 耗时: ' + IntToStr(hslTime) + ' 毫秒 ' );    hsl.Clear;    datePointer : =  Now;     for  I : =   1  to  100000   do     begin        hsl.Insert(i - 1 ' string_ ' + IntToStr(i));    end;    hslTime : =  MilliSecondsBetween(Now, datePointer);    mmo1.Lines.Add( ' 100000 项 THashedStringList 随位置插入耗时: ' + IntToStr(hslTime) + ' 毫秒 ' );    datePointer : =  Now;     for  I : =   1  to  100000   do     begin        hsl.Insert( 0 ' string_ ' + IntToStr(i));    end;    hslTime : =  MilliSecondsBetween(Now, datePointer);    mmo1.Lines.Add( ' 100000 项 THashedStringList 0位置插入耗时: ' + IntToStr(hslTime) + ' 毫秒 ' ); end;procedure TForm1.testTStringList;var    sl: TStringList;  I: Integer;  datePointer: TDateTime;  slTime, slTimeC, slTimeI: Int64;  tempInt: Integer;  tempstr:  string  ;begin     slTime : =   0 ;    slTimeC : =   0 ;    datePointer : =  Now();    sl : =  TStringList.Create;     for  I : =   1  to  200000   do     begin        sl.Add( ' string_ ' + IntToStr(i));    end;    slTime : =  MilliSecondsBetween(Now, datePointer);    mmo1.Lines.Add( ' 200000 项 TStringList 创建耗时: ' + IntToStr(slTime) + ' 毫秒 ' );    datePointer : =  Now;     for  I : =   0  to  200   do     begin        tempInt : =  sl.IndexOf( ' string_ ' + IntToStr(i * 1000 ));    end;    slTime : =  MilliSecondsBetween(Now, datePointer);    mmo1.Lines.Add( ' 200 项字符串搜索 TStringList 耗时: ' + IntToStr(slTime) + ' 毫秒 ' );    datePointer : =  Now;     for  I : =   1  to  200000   do     begin        tempstr : =  sl.Strings[i  - 1 ];    end;    slTime : =  MilliSecondsBetween(Now, datePointer);    mmo1.Lines.Add( ' 200000 项索引搜索 TStringList 耗时: ' + IntToStr(slTime) + ' 毫秒 ' );        datePointer : =  Now;     for  I : =   1  to  100000   do     begin        sl.Insert(i - 1 , ' string_ ' + IntToStr(i));    end;    slTime : =  MilliSecondsBetween(Now, datePointer);    mmo1.Lines.Add( ' 100000 项 TStringList 随位置插入耗时: ' + IntToStr(slTime) + ' 毫秒 ' );    datePointer : =  Now;     for  I : =   1  to  100000   do     begin        sl.Insert( 0 , ' string_ ' + IntToStr(i));    end;    slTime : =  MilliSecondsBetween(Now, datePointer);    mmo1.Lines.Add( ' 100000 项 TStringList 0位置插入耗时: ' + IntToStr(slTime) + ' 毫秒 ' ); end;end.

    编译运行程序,其运行结果:

    200000 项 TStringList 创建耗时:109毫秒200 项字符串搜索 TStringList 耗时:11514毫秒200000 项索引搜索 TStringList 耗时:31毫秒100000 项 TStringList 随位置插入耗时:85828毫秒100000 项 TStringList 0位置插入耗时:148734毫秒--------------------200000 项 THashedStringList 创建耗时:108毫秒200 项字符串搜索 THashedStringList 耗时:188毫秒200000 项索引搜索 THashedStringList 耗时:15毫秒100000 项 THashedStringList 随位置插入耗时:63毫秒100000 项 THashedStringList 0位置插入耗时:55640毫秒

    (测试环境:Windows2003  SP1  +Delphi 2006 Update 2 HotFix1-9 +1G内存 +P-D2.8G双核)

    结果很明显,两者在创建的时候,性能并没有差距(之前听人说THashedStringList在增加和插入操作时会比 TStringList慢,在此并没有显示出来,不知道是不是因为THashedStringList并不是人们说的那样,在每次插入项时都做哈希操作,还请各位不吝赐教),而200 项字符串搜索(从1到2000000项匀距搜索200项)中,两者的性能竟差如此悬殊。其后的各项测试也在预料之中。

    由此可见,THashedStringList能更好的代替我们常用的TStringList来工作,我们为什么要拒绝呢?

    另外,iniFiles单元还提供了TStringHash,但只是对key进行了哈希操作,一般不常用。


    最新回复(0)