我有一个循环中重复调用的操作。使用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结构到本地堆栈制作字符串副本,但事实并非如此。我看不出为什么这应该变慢的原因。任何人都知道这里会发生什么?
答案 0 :(得分:0)
新代码读取的字段被声明为ShortString。从Delphi 5开始,编译器在为大多数字符串操作生成代码之前将ShortStrings转换为长字符串。 (至少,这与非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个字节。相反,它占用保持其长度字节及其字符所需的最小内存量。