问题描述
链接到原始问题,并由Remy Lebeau和RRUZ回答
Linked to the original question Is it possible to get the index of class property? and answered by Remy Lebeau and RRUZ
program Demo;
{$APPTYPE CONSOLE}
uses
System.SysUtils, Winapi.Windows,
System.Rtti, System.TypInfo;
type
TMyClass = class
private
function GetInteger(const Index: Integer): Integer;
procedure SetInteger(const Index, Value: Integer);
public
property P1: Integer Index 1 read GetInteger write SetInteger;
property P2: Integer Index 2 read GetInteger write SetInteger;
property P3: Integer Index 3 read GetInteger write SetInteger;
end;
{ TMyClass }
function TMyClass.GetInteger(const Index: Integer): Integer;
begin
Result := Index;
end;
procedure TMyClass.SetInteger(const Index, Value: Integer);
begin
//
end;
{------------------------------------------------------------------------------}
function GetPropertyIndex(const AClass: TClass; APropertyName: string): Integer;
var
Ctx: TRttiContext;
begin
Ctx := TRttiContext.Create;
Result := (Ctx.GetType(AClass).GetProperty(APropertyName) as TRttiInstanceProperty).Index;
end;
{------------------------------------------------------------------------------}
var
C: Cardinal;
I: Integer;
N: Integer;
begin
try
C := GetTickCount;
for N := 1 to 1000000 do
I := GetPropertyIndex(TMyClass, 'P2');
WriteLn(GetTickCount - C, ' ms - The index of the property P2 is ', I);
ReadLn;
except
on E: Exception do Writeln(E.ClassName, ': ', E.Message);
end;
end.
在我的PC上,此测试大约需要5秒钟。但是当我在调用 GetPropertyIndex()
之前使用 TRttiContext
时-例如
On my PC this test takes ~ 5 sec. But when I use TRttiContext
before calling GetPropertyIndex()
- for example
...
begin
try
TRttiContext.Create.Free;
C := GetTickCount;
for N := 1 to 1000000 do
I := GetPropertyIndex(TMyClass, 'P2');
...
相同测试仅需1秒钟。为什么?
same test takes only ~ 1 sec. Why ?
编辑我在测试secon示例时发现的问题为
Edit The problem I found when I tested secon example as
...
var
Ctx: TRttiContext;
C: Cardinal;
I: Integer;
N: Integer;
begin
try
C := GetTickCount;
for N := 1 to 1000000 do
begin
Ctx := TRttiContext.Create;
I := (Ctx.GetType(TMyClass).GetProperty('P2') as TRttiInstanceProperty).Index;
end;
WriteLn(GetTickCount - C, ' ms - The index of the property P2 is ', I);
ReadLn;
except
on E: Exception do Writeln(E.ClassName, ': ', E.Message);
end;
end.
但是第二个测试中的原因和问题一样明显。
But the reason is more obvious in the second test as is the question.
推荐答案
RTTI数据使用引用计数池进行缓存。您的代码加速得如此之快的原因是, TRttiContext.Create.Free
语句创建了一个临时的 TRttiContext
应用的生命周期范围,并保持对该池的有效引用。在 GetPropertyIndex()
内创建的后续 TRttiContext
实例将重新使用现有池,而不会浪费时间重新创建新池每次池。当DPR代码到达 end。
语句时,临时 TRttiContext
超出范围,并释放其对池的引用
RTTI data is cached using a reference counted pool. The reason your code speeds up so much is because the TRttiContext.Create.Free
statement creates a temp TRttiContext
that stays in scope for the lifetime of your app, maintaining an active reference to that pool. Subsequent TRttiContext
instances created inside of GetPropertyIndex()
are re-using the existing pool and not wasting time re-creating new pools each time. When the DPR code reaches the end.
statement, the temp TRttiContext
goes out of scope and releases its reference to the pool.
当删除 TRttiContext.Create.Free
语句时,临时 TRttiContext
消失,并为 GetPropertyIndex()
使用的每个 TRttiContext
创建和销毁一个新池,浪费时间一遍又一遍地重新创建相同的缓存。
When you remove the TRttiContext.Create.Free
statement, the temp TRttiContext
disappears, and a new pool is created and destroyed for each TRttiContext
that GetPropertyIndex()
uses, wasting time re-creating the same cache over and over.
通过在项目选项中启用调试DCU,然后进入<$,您可以轻松地看到这一点。调试器中的c $ c> TRttiContext 代码。
You can easily see this in action by enabling Debug DCUs in the Project Options and then stepping into the TRttiContext
code in the debugger.
这篇关于为什么提前创建TRttiContext可以使我的RTTI测试运行得更快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!