我有一个在循环中重复调用的操作。使用 TRttiField:
if (field.name = '') or (field.Name[1] <> 'F') then
continue;
分析显示,因此我在 UStrAsg 和 UStrClr 上花费了大量时间。 Field.Name 必须对 TRttiInstanceFieldEx.GetName 进行虚拟调用,后者必须对底层 RTTI 结构的名称执行 UTF8 到字符串的转换。每个循环迭代都会发生两次。
我试图通过绕过字符串转换来消除所有这些:
handle := PFieldExEntry(field.Handle);
if (handle.name = '') or (handle.Name[1] <> 'F') then
continue;
我预计速度会因此提高 5% 左右。相反,循环的执行时间要长几秒,大约慢 20-25%!我检查了生成的 ASM,以确保它没有做任何奇怪的事情,比如将字符串从 RTTI 结构复制到本地堆栈,但事实并非如此。我看不出有什么理由让它变慢。有人知道这里会发生什么吗?
最佳答案
新代码读取的字段被声明为 ShortString。从 Delphi 5 开始,编译器在生成大多数字符串操作的代码之前将 ShortString 转换为长字符串。 (至少,非 Unicode Delphi 就是这样。也许 Unicode Delphi 恢复了一些与 ShortString 相关的优化。)
虽然 TRttiField 包装器可能会利用它正在用每个字符已经占用一个字节的数据填充 UTF-8 字符串的知识,但我预计您的新循环使用的 ShortString-to-string 代码可能会使用更通用的转换例程,并且您要为通用性付出代价。
您可以完全尝试上述字符串转换操作。相反,获取指向第一个字节的指针:
handle := PFieldExEntry(field.Handle);
NameP := PAnsiChar(@handle.name);
if (NameP[0] = #0) or (NameP[1] <> 'F') then
continue;
请注意,虽然它被声明为 ShortString,但它实际上并不是一个。它实际上并不占用256字节。相反,它占用保存其长度字节及其字符所需的最小内存量。
关于delphi - 为什么这种 RTTI 优化会使速度变慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5188310/