Delphi接口性能问题

前端之家收集整理的这篇文章主要介绍了Delphi接口性能问题前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我已经对我的文本编辑器进行了一些非常重要的重构。现在有更少的代码,更容易扩展组件。我非常重视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”引用,现在指向对象实例而不是接口实例。

通过仅调用一个虚拟方法获取动态数组,您可以从循环中消除此开销。现在,您的循环可以通过数组项目,而不需要额外的虚拟接口方法调用的开销。

猜你在找的Delphi相关文章