0

我想重构 DelphiAST以使用接口来处理不同的类型,而不是它现在使用的笨重的 TDirectionary。

一些研究表明,70% 以上的运行时间都花在了字典上。

所以我将制作如下接口:

TSyntaxNode = class
  ...
end;

IIdentifier = interface
  ['{D72E945D-E397-4E02-B702-8AE6C235F9C6}']
  function GetIdentifier: string;
  property Identifier: string read GetIdentifier;
end;

IMethod = interface(Identifier)
  ['{8E6119DC-E0F3-42BD-A5BF-FB658E34499E}']
  .....
end;

TMethodNode = class(TSyntaxNode, IMethod, IIdentifier,...)
 ...
end;

根据罗马的问题是:

引用计数可能会导致性能问题。DelphiAST 创建了数千个类来生成语法树(当输入文件足够大时,超过 100,000 个 TSyntaxNode 实例)。引用计数器会被调用多少次?

每次发生这种情况时try finally都会调用 hidden ,这会减慢速度。

严格使用constin 方法参数可以防止引用计数代码调用该方法,但是每次您执行类似的操作时它仍然会发生MyRef = List[0]- 它会增加分配给 的引用计数MyRef,即使该项目仍然存在于列表中。

如何使用接口而不用担心 refcounting 和 try-finally 块?
我非常乐意手动管理类的破坏。

更多信息
我猜我需要TAggregatedObject用作基础祖先。
而且我在某处读到不分配 GUID 会抑制引用计数,但必须提供资源来支持它。
但是,丢失 GUID 会导致获取子接口时出现问题,因此我必须为此设计一个解决方案....

4

3 回答 3

2

Can I use interfaces without invoking hidden try-finally's?

No. The compiler emits reference counting code with interfaces no matter what. You cannot avoid it.

You can implement you own version of interfaces using a record of function pointers. It will be more clunky but will avoid heap allocation and reference counting.

于 2015-04-26T19:23:05.907 回答
0

“千物”总是让我不寒而栗。内存中的对象有很大的开销。您忘记了它,但是当您尝试管理数千个,或者注意到您的性能下降,或者开始尝试从文件写入或读取时,它会再次弹出......

据我所知,使用接口不会有太大变化,因为您仍然在下面使用对象(类实例)。

这种规模的努力需要专门使用旧的直接内存数据结构。例如,我一直在使用存储在记录数组中的 AST:https ://github.com/stijnsanders/strato

于 2015-04-27T05:50:48.900 回答
0

的 不,如果不调用's 和引用计数,您不能使用接口。 但是,您可以大大减少隐藏异常处理程序的数量。 你只需要非常小心地做两件事。 try-finally

  1. const传递接口时 始终使用参数。

  2. 永远不要将接口存储在接口类型变量中,而是使用自制记录来封装接口,这样它的引用计数就不会被触及。

这是封装记录的示例:

type
  TInterface<Intf: IInterface> = record
  private
    P: Pointer;
  public
    function I: Intf; inline;
    class operator Implicit(const A: Intf): TInterface<Intf>; inline;
  end;

function TInterface<Intf>.I: Intf;
begin
  pointer(IInterface(Result)):= P;
end;

class operator TInterface<Intf>.Implicit(const A: Intf): TInterface<Intf>;
begin
  Result.P:= pointer(IInterface(A));
end;

这是一个演示该概念的示例程序。

program Project32;
{$APPTYPE CONSOLE}

{$R *.res}
uses
  System.SysUtils;

type
  TInterface<Intf: IInterface> = record
  private
    P: Pointer;
  public
    function I: Intf; inline;
    class operator Implicit(const A: Intf): TInterface<Intf>; inline;
  end;

  ITest1 = interface
    function Test1: integer;
  end;

  ITest2 = interface
    function Test2: integer;
  end;

  TTest = class(TAggregatedObject, ITest1, ITest2)
    function Test1: integer;
    function Test2: integer;
  end;

{ TTest }

function TTest.Test1: integer;
begin
  Result:= 1;
end;

function TTest.Test2: integer;
begin
  Result:= 2;
end;

{ TInterface<Intf> }

function TInterface<Intf>.I: Intf;
begin
  pointer(IInterface(Result)):= P;
end;

class operator TInterface<Intf>.Implicit(const A: Intf): TInterface<Intf>;
begin
  Result.P:= pointer(IInterface(A));
end;

var
  I1: TInterface<ITest1>;
  I2: TInterface<ITest2>;
  Test: TTest;

begin
  Test:= TTest.Create(nil);  //Force AV on _AddRef, _Release
  If (Test.Test1 = 1) then WriteLn(S);
  I1:= Test;
  If (I1.I.Test1 =1) then WriteLn(S);
  I2:= Test;
  If (I2.I.Test2 = 2) then WriteLn(S);
  ReadLn(s);
  Test.Free;
end.

TAggregatedObject没有处理_AddRef/_Release调用的接口。
在程序的生命周期中,不会发生任何问题,但是 Delphi 确实将创建过程包装TTest在 try-finally 中,这将在退出函数时产生异常。

在实际使用中,您必须使用 TInterfacedObject。如果您通过很多接口引用它可能会有所帮助。

于 2015-04-28T17:34:36.037 回答