0

我有一个程序我的程序调用了数万次,它使用这样的通用结构:

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 是否更好。我知道理论是尽可能在本地定义,但我想知道在进行数以万计的“创建”和“免费”方面是否有任何问题需要担心?让它们全球化只会做一次创建和一次免费。

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

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

4

3 回答 3

5

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

关于进程速度,简而言之:“过早的优化是万恶之源”——Donald Knuth 引用 CAR Hoare 的话。我确定瓶颈不在. 中TList Create/Free,而是在您的主流程循环中。

因此,在猜测可能发生的变化之前,请使用分析器查看瓶颈在哪里。请参阅Delphi 的 Profiler 和内存分析工具

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

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

于 2012-06-30T09:05:54.190 回答
2

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

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

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

于 2012-06-30T03:51:06.570 回答
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;

Dsomeprocess((PeopleIncluded) 也必须知道记录。在多个地方声明相同的记录有点糟糕。这就是为什么你想让它对 Dsomeprocess 可用。但是,最好在本地声明变量。

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

于 2012-06-30T09:40:36.320 回答