【发布时间】:2010-11-03 13:12:39
【问题描述】:
我需要 Delphi 2009 中最快的散列函数,它将从 Unicode 字符串创建散列值,该字符串将相当随机地分布到存储桶中。
我最初是从 GpStringHash 中 Gabr 的 HashOf 函数开始的:
function HashOf(const key: string): cardinal;
asm
xor edx,edx { result := 0 }
and eax,eax { test if 0 }
jz @End { skip if nil }
mov ecx,[eax-4] { ecx := string length }
jecxz @End { skip if length = 0 }
@loop: { repeat }
rol edx,2 { edx := (edx shl 2) or (edx shr 30)... }
xor dl,[eax] { ... xor Ord(key[eax]) }
inc eax { inc(eax) }
loop @loop { until ecx = 0 }
@End:
mov eax,edx { result := eax }
end; { HashOf }
但我发现这并没有从 Unicode 字符串中产生好的数字。我注意到 Gabr 的例程没有更新到 Delphi 2009。
然后我在 Delphi 2009 的 SysUtils 中发现了 HashNameMBCS,并将其翻译成这个简单的函数(其中“string”是 Delphi 2009 的 Unicode 字符串):
function HashOf(const key: string): cardinal;
var
I: integer;
begin
Result := 0;
for I := 1 to length(key) do
begin
Result := (Result shl 5) or (Result shr 27);
Result := Result xor Cardinal(key[I]);
end;
end; { HashOf }
我认为这很好,直到我查看 CPU 窗口并看到它生成的汇编代码:
Process.pas.1649: Result := 0;
0048DEA8 33DB xor ebx,ebx
Process.pas.1650: for I := 1 to length(key) do begin
0048DEAA 8BC6 mov eax,esi
0048DEAC E89734F7FF call $00401348
0048DEB1 85C0 test eax,eax
0048DEB3 7E1C jle $0048ded1
0048DEB5 BA01000000 mov edx,$00000001
Process.pas.1651: Result := (Result shl 5) or (Result shr 27);
0048DEBA 8BCB mov ecx,ebx
0048DEBC C1E105 shl ecx,$05
0048DEBF C1EB1B shr ebx,$1b
0048DEC2 0BCB or ecx,ebx
0048DEC4 8BD9 mov ebx,ecx
Process.pas.1652: Result := Result xor Cardinal(key[I]);
0048DEC6 0FB74C56FE movzx ecx,[esi+edx*2-$02]
0048DECB 33D9 xor ebx,ecx
Process.pas.1653: end;
0048DECD 42 inc edx
Process.pas.1650: for I := 1 to length(key) do begin
0048DECE 48 dec eax
0048DECF 75E9 jnz $0048deba
Process.pas.1654: end; { HashOf }
0048DED1 8BC3 mov eax,ebx
这似乎包含比 Gabr 的代码更多的汇编代码。
速度至关重要。我可以做些什么来改进我编写的 pascal 代码或我的代码生成的汇编程序?
跟进。
我终于选择了基于 SysUtils.HashNameMBCS 的 HashOf 函数。它似乎为 Unicode 字符串提供了良好的散列分布,而且速度似乎相当快。
是的,生成了很多汇编代码,但是生成它的 Delphi 代码非常简单,并且只使用位移操作,所以很难相信它不会很快。
【问题讨论】:
-
在你最后的 HashOf 中,我应该从 1 变为 Length(key)。
-
@gabr:谢谢。我现在看到我写了“跟进”,甚至没有意识到我最终使用了与我的问题相同的功能,除了我在跟进中犯了错误。我会重写的。
标签: delphi unicode assembly hash delphi-2009