Delphi 我可以使用接口而不调用隐藏的try finally';s
我想使用接口来处理不同的类型,而不是笨重的类型 t它现在使用的方向 显示70%以上的运行时间花费在字典中 因此,我将制作如下界面:Delphi 我可以使用接口而不调用隐藏的try finally';s,delphi,interface,refcounting,Delphi,Interface,Refcounting,我想使用接口来处理不同的类型,而不是笨重的类型 t它现在使用的方向 显示70%以上的运行时间花费在字典中 因此,我将制作如下界面: TSyntaxNode = class ... end; IIdentifier = interface ['{D72E945D-E397-4E02-B702-8AE6C235F9C6}'] function GetIdentifier: string; property Identifier: string read GetIdentifier;
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创建数千个类来生成语法树(当输入文件足够大时,超过100000个TSyntaxNode实例)。引用计数器将被调用多少次
每次发生这种情况时,都会调用一个隐藏的try finally
,这将大大降低速度
在方法参数中严格使用const
可以防止refcount代码调用该方法,但如果每次执行类似于MyRef=List[0]
的操作时都会发生这种情况,即使该项仍然存在于列表中,它也会增加分配给MyRef
的refcount
如何在不必担心重新计数和最后尝试块的情况下使用接口?我非常乐意手动管理类的销毁 进一步信息
我猜我需要使用
TAggregatedObject
作为基本祖先。我在某个地方读到,不分配GUID会禁止引用计数,但必须使用源代码来备份引用计数。
然而,丢失GUID将导致在获取子接口时出现问题,因此我必须设计解决方案 我可以在不调用隐藏的try finally的情况下使用接口吗 不可以。不管发生什么,编译器都会通过接口发出引用计数代码。你无法避免 您可以使用函数指针的记录来实现自己版本的接口。它将更加笨重,但将避免堆分配和引用计数 “成千上万的物体”总是让我不寒而栗。内存中的对象有很大的开销。您忘记了它,但当您试图管理数千个时,或者注意到它的性能下降,或者开始尝试从文件中写入或读取时,它会再次弹出 据我所知,使用接口不会有太大变化,因为您仍然在下面使用对象(类实例) 这种规模的努力需要特定地使用良好的旧的直接到内存的数据结构。例如,我一直在玩一个存储在记录数组中的AST:是否如果不调用
try finally
和refcounting,您就不能使用接口。但是,您可以大大减少隐藏异常处理程序的数量。
你只需要非常小心地做两件事
const
参数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;
类型
TInterface=记录
私有的
P:指针;
公众的
功能一:Intf;内联;
类运算符隐式(常量A:Intf):TInterface;内联;
结束;
函数TInterface.I:Intf;
开始
指针(界面(结果)):=P;
结束;
类运算符TInterface.Implicit(常量A:Intf):TInterface;
开始
结果.P:=指针(界面(A));
结束;
这里有一个示例程序来演示这个概念
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.
程序项目32;
{$APPTYPE控制台}
{$R*.res}
使用
System.SysUtils;
类型
TInterface=记录
私有的
P:指针;
公众的
功能一:Intf;内联;
类运算符隐式(常量A:Intf):TInterface;内联;
结束;
ITest1=接口
函数Test1:整数;
结束;
ITest2=接口
函数Test2:整数;
结束;
TTest=class(TAggregatedObject、ITest1、ITest2)
函数Test1:整数;
函数Test2:整数;
结束;
{TTest}
函数TTest.Test1:整数;
开始
结果:=1;
结束;
函数TTest.Test2:整数;
开始
结果:=2;
结束;
{TInterface}
函数TInterface.I:Intf;
开始
指针(界面(结果)):=P;
结束;
类运算符TInterface.Implicit(常量A:Intf):TInterface;
开始
结果.P:=指针(界面(A));
结束;
变量
I1:着色面;
I2:着色面;
试验:TTest;
开始
测试:=测试创建(无)//强制AV打开_AddRef,_释放
如果(Test.Test1=1),则写入n;
I1:=试验;
如果(I1.I.Test1=1),则写入n(S);
I2:=试验;
如果(I2.I.Test2=2),则写入n(S);
ReadLn(s);
免费测试;
结束。
TAggregatedObject
没有处理\u AddRef
/\u Release
调用的接口。在程序的生命周期内,不会出现任何问题,但是Delphi会将
TTest
的创建包装在try finally中,这将在退出函数时生成异常
在实际使用中,您必须使用TInterfacedObject。不过,如果您经常传递接口引用,可能会有所帮助 是的,这会起作用,我记得在一个delphi博客中看到过类似的东西,但不记得在哪里。只需声明一个包含函数指针成员的记录。手动实现的接口。这里有一些关于如何使用记录实现接口的信息:但我希望接口的接口部分消失,所以try最终消失。将
MyRef
声明为指针。赋值语句将起作用。当需要访问接口的方法时,键入cast将其转换为所需的接口类型。类型转换不会导致引用计数。您正在向错误的方向优化。在DelphiAST中优化代码的方法是使用多态性,因为这就是它的用途。为什么DelphiAST甚至使用泛型?@SilverWarior,泛型不会导致缓慢,可能是代码膨胀,但不会导致缓慢。这不是问题的真正答案,但我对您的解决方案很好奇。顺便说一句,德尔夫的缓慢