Delphi接口性能问题
发布时间:2020-12-15 10:18:26 所属栏目:大数据 来源:网络整理
导读:我已经对我的文本编辑器进行了一些非常重要的重构。现在有更少的代码,更容易扩展组件。我非常重视OO设计,比如抽象类和接口。不过,在表现方面,我注意到了一些损失。问题是阅读大量的记录。当所有事情发生在同一个对象内部时,速度很快,但是通过界面完成
我已经对我的文本编辑器进行了一些非常重要的重构。现在有更少的代码,更容易扩展组件。我非常重视OO设计,比如抽象类和接口。不过,在表现方面,我注意到了一些损失。问题是阅读大量的记录。当所有事情发生在同一个对象内部时,速度很快,但是通过界面完成时速度很慢。我做了最小的程序来说明细节:
unit Unit3; interface uses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs; const N = 10000000; type TRecord = record Val1,Val2,Val3,Val4: integer; end; TArrayOfRecord = array of TRecord; IMyInterface = interface ['{C0070757-2376-4A5B-AA4D-CA7EB058501A}'] function GetArray: TArrayOfRecord; property Arr: TArrayOfRecord read GetArray; end; TMyObject = class(TComponent,IMyInterface) protected FArr: TArrayOfRecord; public procedure InitArr; function GetArray: TArrayOfRecord; end; TForm3 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form3: TForm3; MyObject: TMyObject; implementation {$R *.dfm} procedure TForm3.FormCreate(Sender: TObject); var i: Integer; v1,v2,f: Int64; MyInterface: IMyInterface; begin MyObject := TMyObject.Create(Self); try MyObject.InitArr; if not MyObject.GetInterface(IMyInterface,MyInterface) then raise Exception.Create('Note to self: Typo in the code'); QueryPerformanceCounter(v1); // APPROACH 1: NO INTERFACE (FAST!) // for i := 0 to high(MyObject.FArr) do // if (MyObject.FArr[i].Val1 < MyObject.FArr[i].Val2) or // (MyObject.FArr[i].Val3 < MyObject.FArr[i].Val4) then // Tag := MyObject.FArr[i].Val1 + MyObject.FArr[i].Val2 - MyObject.FArr[i].Val3 // + MyObject.FArr[i].Val4; // END OF APPROACH 1 // APPROACH 2: WITH INTERFACE (SLOW!) for i := 0 to high(MyInterface.Arr) do if (MyInterface.Arr[i].Val1 < MyInterface.Arr[i].Val2) or (MyInterface.Arr[i].Val3 < MyInterface.Arr[i].Val4) then Tag := MyInterface.Arr[i].Val1 + MyInterface.Arr[i].Val2 - MyInterface.Arr[i].Val3 + MyInterface.Arr[i].Val4; // END OF APPROACH 2 QueryPerformanceCounter(v2); QueryPerformanceFrequency(f); ShowMessage(FloatToStr((v2-v1) / f)); finally MyInterface := nil; MyObject.Free; end; end; { TMyObject } function TMyObject.GetArray: TArrayOfRecord; begin result := FArr; end; procedure TMyObject.InitArr; var i: Integer; begin SetLength(FArr,N); for i := 0 to N - 1 do with FArr[i] do begin Val1 := Random(high(integer)); Val2 := Random(high(integer)); Val3 := Random(high(integer)); Val4 := Random(high(integer)); end; end; end. 当我直接读取数据时,我得到0.14秒的时间。但是当我通过界面,需要1.06秒。 有没有办法实现与以前的新设计相同的表现? 我应该提到,我试图设置PArrayOfRecord = ^ TArrayOfRecord并重新定义IMyInterface.arr:PArrayOfRecord并在for循环中写入Arr ^等。这帮了很多然后我得到了0.22秒。但它还不够好。什么使它开始这么慢? 解决方法
在迭代元素之前,将数组简单地分配给局部变量。
你看到的是接口方法调用是虚拟的,必须通过间接方式调用。此外,代码必须传递一个“thunk”,它修复了“Self”引用,现在指向对象实例而不是接口实例。 通过仅调用一个虚拟方法来获取动态数组,您可以从循环中消除此开销。现在,您的循环可以通过数组项目,而不需要额外的虚拟接口方法调用的开销。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |