本文介绍了为什么提前创建TRttiContext可以使我的RTTI测试运行得更快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

链接到原始问题,并由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测试运行得更快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-21 09:37