在Delphi中声明本地或全球?

时间:2012-06-30 02:31:30

标签: delphi scope global-variables local-variables

我的程序调用数万次,使用这样的通用结构:

procedure PrintIndiEntry(JumpID: string);

type
  TPeopleIncluded = record
    IndiPtr: pointer;
    Relationship: string;
  end;

var
  PeopleIncluded: TList<TPeopleIncluded>;
  PI: TPeopleIncluded;

begin { PrintIndiEntry }

  PeopleIncluded := TList<TPeopleIncluded>.Create;

 { A loop here that determines a small number (up to 100) people to process }
  while ... do begin

    PI.IndiPtr := ...;
    PI.Relationship := ...;
    PeopleIncluded.Add(PI);

  end;

  DoSomeProcess(PeopleIncluded);

  PeopleIncluded.Clear;
  PeopleIncluded.Free;

end { PrintIndiEntry }

或者,我可以在全局而不是本地声明PeopleIncluded,如下所示:

unit process;

interface

type
  TPeopleIncluded = record
    IndiPtr: pointer;
    Relationship: string;
  end;

var
  PeopleIncluded: TList<TPeopleIncluded>;
  PI: TPeopleIncluded;

procedure PrintIndiEntry(JumpID: string);

begin { PrintIndiEntry }

 { A loop here that determines a small number (up to 100) people to process }
  while ... do begin

    PI.IndiPtr := ...;
    PI.Relationship := ...;
    PeopleIncluded.Add(PI);

  end;

  DoSomeProcess(PeopleIncluded);

  PeopleIncluded.Clear;

end { PrintIndiEntry }

procedure InitializeProcessing;
begin
  PeopleIncluded := TList<TPeopleIncluded>.Create;
end;

procedure FinalizeProcessing;
begin
  PeopleIncluded.Free;
end;

我的问题是,在这种情况下,最好是全局声明PeopleIncluded而不是本地声明。我知道理论是尽可能在本地定义,但我想知道是否有任何问题需要担心成千上万的“创造”和“免费”?使它们成为全球只会创造一个创造,一个免费。

在这种情况下使用的推荐方法是什么?

如果推荐的方法仍然在本地定义,那么我想知道在本地定义仍然是一个选项时是否有更好的全局定义。

3 个答案:

答案 0 :(得分:5)

关于流程的可见性,我要做的是创建一个 class保存所有数据,一个用于初始化的方法和一个析构函数,然后一个方法来调用该流程。然后使用分析器优化速度。 从不使用全局,但将您的进程封装在小型可重用和多线程就绪的类中。

关于流程速度,简而言之:“过早优化是所有邪恶的根源” - 唐纳德克努特,引用C. A. R. Hoare。我确信TList Create/Free中的瓶颈不是,而是在主流程循环中。

因此,在猜测可能发生的变化之前,请先使用分析器查看瓶颈所在。见Profiler and Memory Analysis Tools for Delphi

您可以预先分配变量和/或缓存可重用数据,使用静态数组而不是TList(或分配它并使用外部count变量重用它),并避免分配{ {1}}个实例(并且没有string参数传递它们)。但也许不是一个神奇的解决方案。

为了加快处理速度,更改算法几乎总是比你尝试的一些低级实现技巧更好。使用预先计算的查找表,内存预分配,避免创建临时const(例如使用string代替PosEx子链;或混合copy / AnsiString),避免磁盘,API或DB调用,更改内存结构,排序数据然后使用二进制搜索,使用散列或非管道循环,让你处理多线程等等......这是不可能的猜测如果没有流程的完整源代码就应该更改,并在真实数据上运行探查器!

答案 1 :(得分:2)

你的第一个代码更好。从外部隐藏任何数据结构是很好的。第一个代码显示PeopleIncluded不在您的程序之外使用,因此最好将其保留在其中。将其暴露在外面(在界面部分中)将使其可以从使用该单元的所有其他单元中看到。通过这样做,您可能会被其他单位访问和修改。这可能是您或其他人使用您的代码有意或无意地发生的,并可能导致不良后果。

如果你不能或仍然想让它不是你的程序的本地,最好在实现部分中声明类型和var,而不是接口部分。

您不必担心性能问题。内存中的操作很快,我的建议只是在性能瓶颈真正发生时才会担心。当它发生时,您可以分析您的应用程序以找到瓶颈,并仅优化导致瓶颈的代码。这样做可以避免不必要的努力来优化对您的应用程序性能没有贡献(或最小化)的代码。

答案 2 :(得分:1)

案例#3

unit process;

interface

type
  TPeopleIncluded = record
    IndiPtr: pointer;
    Relationship: string;
  end;


procedure PrintIndiEntry(JumpID: string);
var
  PeopleIncluded: TList<TPeopleIncluded>;
  PI: TPeopleIncluded;

begin { PrintIndiEntry }

 { A loop here that determines a small number (up to 100) people to process }
  while ... do begin

    PI.IndiPtr := ...;
    PI.Relationship := ...;
    PeopleIncluded.Add(PI);

  end;

  DoSomeProcess(PeopleIncluded);

  PeopleIncluded.Clear;

end { PrintIndiEntry }

procedure InitializeProcessing;

Dosomeprocess((PeopleIncluded)也必须知道记录。在多个地方声明相同的记录有点不好。这就是为什么你想让它可用于Dosomeprocess。但是这些变量在本地更好地声明。

创建一个小班可能是最好的。