问题
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.
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');
...
same test takes only ~ 1 sec. Why ?
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.
回答1:
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.
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.
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.
来源:https://stackoverflow.com/questions/19722394/why-does-creating-a-trtticontext-in-advance-make-my-rtti-tests-run-faster