首页 文章

在Delphi中初始化数组的更快方法

提问于
浏览
6

我试图在我的Delphi应用程序中挤压每一点性能,现在我开始使用一个与动态数组一起工作的程序 . 最慢的一行是

SetLength(结果,Len);

用于初始化动态数组 . 当我查看SetLength过程的代码时,我发现它远非最佳 . 呼叫顺序如下:

_DynArraySetLength - > DynArraySetLength

DynArraySetLength获取数组长度(初始化为零),然后使用ReallocMem,这对于启动也是不必要的 .

我一直在做SetLength来初始化动态数组 . 也许我错过了什么?有更快的方法吗?

编辑:描述主算法将占用大量空间,实际上是不必要的,因为它是车辆路径问题(http://en.wikipedia.org/wiki/Vehicle_routing_problem)的证明 . 我确实需要数以万计的分配,因为我必须保留所有数据,并将其分开保存 . Probalby如果我能想到一些聪明的数据结构会有所帮助,但我能想到的任何东西都会大大增加代码的复杂性 . 基本上我试图从低级别的东西中获得我能做的一切.1504184_m所以这是一个相当狭隘的问题:是否有可能增加这个特定的电话 . 我认为要做到这一点,我需要根据SetLength代码编写自己的初始化函数 . 并使其内联 .

6 回答

  • 2

    Max写道:我对一个函数执行了多次调用,该函数执行一次SetLength(Result,Len) .

    检查你如何使用你的函数:你真的需要对这个分配函数进行大量不同的调用吗?你可以像弗朗索瓦建议的那样,重新设计你的代码以减少通话次数吗?

    如果你真的需要对你的函数进行一次大量的不同调用,并且需要加快速度,我认为你需要保留动态数组并使用不同的结构 .

    但在此之前,并进入一个完整的调试地狱,我会强烈加入弗朗索瓦的建议,并尝试重新设计代码 .

    也许您可以告诉我们更多关于您的算法的信息?它是关于处理图形3D结构?

    [编辑]好的,如果它是关于解决NP完全问题,我会尽量避免分配 .

    大多数情况下,您可以给出数组/堆栈/结构大小的上限 - 例如:#cities,#carsh #drivers,#roads * #cities ...

    对于那些部分,我建议分配一次最大可能的数组,并手动处理你只使用前n行等的事实 .

    考虑到之后可以节省的计算时间,即使在n ^ 2或n ^ 3中分配结构也是可以接受的 .

    优化SetLength:你的建议是有道理的 .

    但是,如果动态数组非常适合编写Delphi代码 - 主要是因为它们的语义 - 它们,恕我直言,不能很好地适应高性能计算 - 它在很大程度上依赖于RTTI,引用计数可以偶尔给你带来惊喜 . ..
    你的建议是动态数组语义的变化 . 尝试查看解决方案"changing your data type"是否真的无法编写和调试 .

  • 10

    这是一个更多的评论,但由于在评论中发布大量代码并不漂亮,我在此处发布 .

    有时,如果您不知道最终会有多少元素,那么编写这样的代码可能很诱人:

    var
      Arr: array of cardinal;
    
    procedure AddElement(const NewElement: cardinal);
    begin
      SetLength(Arr, length(Arr) + 1);
      Arr[high(Arr)] := NewElement;
    end;
    

    这非常糟糕,因为每次添加新元素时都需要重新分配内存 . 更好的方法(如果可能)是找到元素数量的上限,例如MAX_ELEMENTS = 100000;然后最初设置长度:

    SetLength(Arr, MAX_ELEMENTS);
    

    然后你创建一个变量

    var
      ActualNumberOfElements: cardinal = 0;
    

    和写

    procedure AddElement(const NewElement: cardinal);
    begin
      Arr[ActualNumberOfElements] := NewElement;
      inc(ActualNumberOfElements);
    end;
    

    完成填充数组后,只需截断它:

    SetLength(Arr, ActualNumberOfElements);
    
  • 3

    如果你只是打电话一次并且需要很长时间,那么你要求的RAM比现有的多,这会导致操作系统换出其他东西以试图为你腾出空间 . 修复:添加更多RAM,使用更小的阵列 .

    如果你在一个循环中调用它,那么“realloc”就是问题所在 . 每次调用它时,逐渐增加数组的长度,Delphi重新分配整个数组,然后它将所有内容从旧数组复制到新数组 . 效率不高 .

  • 2

    Premature optimization is the root of all evil.
    我怀疑你不得不关心一生一次的初始化......
    除非你称之为无数次,否则我建议你重新设计你的代码 .

  • 1

    而不是多次调用包含 SetLength 的函数,而是预先分配存储,并将预分配的数组传递给函数 . 一种这样的方式是这样的:

    const
      NUM_ARRAYS = 1000;
      ARRAY_SIZE = 1000;
    type
      TMyArray = array [0..ARRAY_SIZE] of Integer;
    var
      MyStorage: array[0..NUM_ARRAYS] of TMyArray;
    
    procedure DoWork(var AArray: TMyArray);
    begin
      Blah;
    end;
    
    procedure MainLoop;
    var
      i: Integer;
    begin
      for i := 0 to High(MyStorage) do
      begin
        DoWork(MyStorage[i]);
      end;
    end;
    

    这比在内循环中调用SetLength要快得多 . 需要注意的主要是为硬件使用太多内存 .

  • 2

    SetLength中最慢的部分不是“无法调用”或其他东西 - 它是由内存管理器执行的内存分配(在你的情况下,ReallocMem将是简单的GetMem,因为源指针是nil) .

    那么,你使用什么内存管理器?在没有FastMM的情况下,你是D7吗?

    尝试安装FastMM,看看它是否有所帮助 .

相关问题