And*_*and 14 delphi compiler-construction string performance
这是常识,SameStr(S1, S2)
比快S1 = S2
,在var S1, S2: string
Delphi中.
(而且,当然,SameText(S1, S2)
要快得多AnsiLowerCase(S1) = AnsiLowerCase(S2)
.)
但是,据我所知,SameStr(S1, S2)
它完全相同S1 = S2
,所以我不禁想知道为什么Delphi编译器在使用运算符SameStr
测试字符串相等时不使用代码=
.当然必须有这个原因吗?
一个简单的程序,
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils,
RejbrandCommon;
const
N = 1000000;
var
Strings1, Strings2: StringArray;
i: integer;
b: {dummy }boolean;
procedure CreateRandomStringArrays;
var
i: integer;
begin
SetLength(Strings1, N);
SetLength(Strings2, N);
for i := 0 to N - 1 do
begin
Strings1[i] := RandomString(0, 40);
Strings2[i] := RandomString(0, 40);
end;
end;
begin
CreateRandomStringArrays;
StartClock;
for i := 0 to N - 1 do
if Strings1[i] = Strings2[i] then
b := not b;
StopClock;
OutputClock;
StartClock;
for i := 0 to N - 1 do
if SameStr(Strings1[i], Strings2[i]) then
b := not b;
StopClock;
OutputClock;
Pause;
end.
Run Code Online (Sandbox Code Playgroud)
哪里
function RandomString(const LowerLimit: integer = 2; const UpperLimit: integer = 20): string;
var
N, i: integer;
begin
N := RandomRange(LowerLimit, UpperLimit);
SetLength(result, N);
for i := 1 to N do
result[i] := RandomChar;
end;
Run Code Online (Sandbox Code Playgroud)
和内联
function RandomChar: char;
begin
result := chr(RandomRange(ord('A'), ord('Z')));
end;
Run Code Online (Sandbox Code Playgroud)
和"时钟"的功能只是包装QueryPerformanceCounter
,QueryPerformanceFrequency
以及Writeln
,产生输出
2.56599325762716E-0002
1.24310093156453E-0002
ratio ~ 2.06
Run Code Online (Sandbox Code Playgroud)
如果我们比较的两个弦的长度差异很大,则差异甚至更大.我们试图
Strings1[i] := RandomString(0, 0); // = '';
Strings2[i] := RandomString(0, 40);
Run Code Online (Sandbox Code Playgroud)
并获得
1.81630411160156E-0002
4.44662043198641E-0003
ratio ~ 4.08
Run Code Online (Sandbox Code Playgroud)
那么SameStr
编写汇编时编译器为什么不使用代码S1 = S2
呢?
在阅读了Cosmin Prund的优秀答案之后,我无法抗拒设定
Strings1[i] := RandomString(40, 40);
Strings2[i] := RandomString(40, 40);
Run Code Online (Sandbox Code Playgroud)
产生相同长度的字符串.
2.74783364614126E-0002
1.96818773095322E-0002
ratio ~ 1.40
Run Code Online (Sandbox Code Playgroud)
嗯... SameStr
仍然赢...
CPU Brand String: Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz
Memory: 6 GB
OS: Windows 7 Home Premium (64-bit)
Compiler/RTL: Delphi 2009
Run Code Online (Sandbox Code Playgroud)
看起来好像(参见Cosmin Prund的优秀答案下面的评论),=
操作员在D2009和D2010之间进行了更改.谁能证实这一点?
Cos*_*und 19
这一切都取决于你如何构建随机字符串.我使用了代码的修改版本,因为我们很少有RejbrandCommon单元,因为我想使用Excel来完成我的分析(并制作漂亮的图片).
代码(跳过代码看一些结论):
程序Project3;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
const
StringsNumber = 2000000;
var
Strings1, Strings2: array of string;
StrLen: integer;
b: {dummy }boolean;
function RandomString(MinLen, MaxLen:Integer):string;
var N, i:Integer;
begin
N := MinLen + Random(MaxLen-MinLen);
Assert(N >= MinLen); Assert(N <= MaxLen);
SetLength(Result, N);
for i:=1 to N do
Result[i] := Char(32 + Random(1024)); // Random Unicode Char
end;
procedure CreateRandomStringArrays(StrLen:Integer);
var
i: integer;
StrLen2:Integer;
begin
SetLength(Strings1, StringsNumber);
SetLength(Strings2, StringsNumber);
for i := 0 to StringsNumber - 1 do
begin
StrLen2 := StrLen + Random(StrLen div 2);
Strings1[i] := RandomString(StrLen, StrLen2);
StrLen2 := StrLen + Random(StrLen div 2);
Strings2[i] := RandomString(StrLen, StrLen2);
end;
end;
var C1, C2, C3, C4:Int64;
procedure RunTest(StrLen:Integer);
var i:Integer;
begin
CreateRandomStringArrays(StrLen);
// Test 1: using equality operator
QueryPerformanceCounter(C1);
for i := 0 to StringsNumber - 1 do
if Strings1[i] = Strings2[i] then
b := not b;
QueryPerformanceCounter(C2);
// Test 2: using SameStr
QueryPerformanceCounter(C3);
for i := 0 to StringsNumber - 1 do
if SameStr(Strings1[i], Strings2[i]) then
b := not b;
QueryPerformanceCounter(C4);
// Results:
C2 := C2 - C1;
C4 := C4 - C3;
WriteLn(IntToStr(StrLen) + #9 + IntToStr(C2) + #9 + IntToStr(C4));
end;
begin
WriteLn('Count'#9'='#9'SameStr');
for StrLen := 1 to 50 do
RunTest(StrLen);
end.
Run Code Online (Sandbox Code Playgroud)
我使CreateRandomStringArrays
例程采用了StrLen参数,因此我可以在循环中运行多个类似的测试.我QueryPerformanceCounter
直接使用了代码WriteLn
,结果采用制表符分隔格式,因此我可以将其复制/粘贴到Excel中.在Excel中,我得到以下形式的结果:
StrLen = SameStr 1 61527 69364 2 60188 69450 3 72130 68891 4 78847 85779 5 77852 78286 6 83612 88670 7 93936 96773
然后我对事情进行了规范化.在每一行上,最大值为"1",另一个值为1的百分比.结果如下所示:
StrLen = SameStr 1 0,88 1 2 0,86 1 3 1 0,95 4 0,91 1 5 0,99 1 6 0,94 1 7 0,97 1
然后我开始玩CreateRandomStringArrays
例程来运行多个测试.
这就是原始情况下情节的样子(CreateRandomStringArrays生成随机长度的字符串,长度为1到X轴上的任何内容).蓝色是"="运算符的结果,红色是"SameStr"的结果,越低越好.很明显,SameStr()的字符串边长超过10个字符.
替代文字http://fisiere.sediu.ro/PentruForumuri/V1_1_to_maxlen.png
接下来的测试,制作CreateRandomStringArrays
EQUAL长度的返回字符串.字符串的内容仍然是完全随机的,但字符串的长度等于X轴上的任何内容.这次"="运算符显然更有效:
alt text http://fisiere.sediu.ro/PentruForumuri/V1_equal_strings.png
现在真正的问题是,使用REAL代码,字符串相等的概率是多少?SameStr()开始获取地形的差异有多大?接下来的文字,我正在构建两个字符串,第一个是StrLen(X轴上的数字),第二个字符串的长度为StrLen + Random(4).同样,"="运算符更好:
alt text http://fisiere.sediu.ro/PentruForumuri/V1_rnd_p4.png
接下来的测试,我有两个字符串,每个字符串长度为:StrLen + Random(StrLen div 10)."="运算符更好.
替代文字http://fisiere.sediu.ro/PentruForumuri/V1_rnd_pm_10p.png
......和我的最终测试,长度为+/- 50%的字符串.公式:StrLen + Random(StrLen div 2).该SameStr()
赢这一轮:
替代文字http://fisiere.sediu.ro/PentruForumuri/V1_rnd_pm_50p.png
我不确定.我没想到这与字符串长度有关!我希望这两个函数能够快速处理不同长度的字符串,但它不会发生.
SameStr 有一个可选的第三个参数:LocaleOptions。通过省略第三个参数,您可以获得类似于“=”的行为:区分大小写的区域设置独立比较。
您可能认为这与二进制比较相同,但事实并非如此。
从 D2009 开始,除了长度和引用计数之外,Delphi 字符串还具有“代码页”有效负载。
StrRec = packed record
codePage: Word;
elemSize: Word;
refCnt: Longint;
length: Longint;
end;
Run Code Online (Sandbox Code Playgroud)
当您执行 a 时,String1 = String2
您是在告诉编译器忽略有关字符串的所有信息并简单地进行二进制比较(它使用 UStrEqual 进行比较)。
当您执行SameStr
or CompareStr
(由 SameStr 使用)时,Delphi 将首先检查字符串是否为 Unicode (UTF-16LE),如果不是,则在执行实际工作之前将其转换。
当您查看 CompareStr(没有第三个参数的那个)的实现时,您可以看到这一点,它在初始优化之后检查参数是否是 unicode 字符串,如果不是,则使用 UStrFromLStr 进行转换。
更新:
实际上,UStrEqual(通过 UStrCmp)也进行转换,就像 CompareStr 一样,它查看字符串的 elemSize 来确定它们是否是 Unicode,如果不是,则进行转换。
因此,编译器不使用 SameStr (CompareStr) 作为运算符的原因=
目前令我困惑。我唯一能想到的是,它与用于“=”比较 AnsiStrings 的 LStrEqual 有一个很好的类比。我想只有编译器人才知道。
抱歉浪费了您的时间。不过,我会留下答案,这样其他人就不必走这条调查路线了。
归档时间: |
|
查看次数: |
2820 次 |
最近记录: |