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をローカルではなくグローバルに宣言する方がよいかどうかです。理論は可能な限りローカルで定義することだと知っていますが、何万もの「作成」と「無料」を行うことに関して心配すべき問題があるかどうか知りたいですか?それらをグローバルにすると、作成は1回、無料は1回だけになります。

この場合に使用する推奨される方法は何ですか?

推奨される方法がまだローカルで定義することである場合、ローカルで定義することがまだオプションであるときにグローバルに定義する方が良い状況があるかどうか疑問に思います。

4

3 に答える 3

5

プロセスの可視性について、私が作成するのは、すべてのデータを保持するものを作成する classことです。1つは初期化用のメソッド、もう1つはデストラクタ、次にプロセスを呼び出すための1つのメソッドです。次に、プロファイラーを使用して速度を最適化します。グローバルを使用しないでください。ただし、プロセスを再利用可能でマルチスレッド対応の小さなクラスにカプセル化してください

要するに、プロセス速度について:「時期尚早の最適化はすべての悪の根源です」—ドナルド・クヌース、CARHoareの引用。ボトルネックはではなくTList Create/Freeメインプロセスループ内にあると確信しています。

したがって、何が変更される可能性があるかを推測する前に、プロファイラーを使用してボトルネックがどこにあるかを確認してください。Delphi用のプロファイラおよびメモリ分析ツールを参照してください

変数を事前に割り当てたり、再利用可能なデータをキャッシュしたり、の代わりに静的配列を使用しTListたり(または、外部count変数を使用して割り当てて再利用したり)、インスタンスの割り当てを回避したり(パラメーターstringなしで渡す)することができます。constしかし、おそらく魔法の解決策ではありません。

プロセスを高速化するために、アルゴリズムを変更することは、ほとんどの場合、あなたが試したようないくつかの低レベルの実装トリックよりも優れています。事前に計算されたルックアップテーブルの使用、メモリの事前割り当て、一時的な作成の回避string(たとえば、サブチェーンのPosEx代わりに使用、または/の混合)、ディスク、API、またはDB呼び出しの回避、メモリ構造の変更、データの並べ替え、バイナリ検索の使用、ハッシュまたはパイプライン解除ループを使用し、マルチスレッドを処理するなど...プロセスのソースコード全体がないと何を変更すべきかを推測し、実際のデータでプロファイラーを実行することは不可能です。copyAnsiStringUnicodeString

于 2012-06-30T09:05:54.190 に答える
2

最初のコードの方が優れています。データ構造を外部から隠すのは良いことです。最初のコードは、PeopleIncludedがプロシージャの外部で使用されていないことを示しているため、内部に保持することをお勧めします。外部(インターフェースセクション)に公開すると、このユニットを使用する他のすべてのユニットから見えるようになります。そうすることで、他のユニットからアクセスされたり変更されたりする危険があります。これは、あなたまたはあなたのコードを使用している他の人々によって意図的または意図せずに発生する可能性があり、望ましくない結果を引き起こす可能性があります。

プロシージャに対してローカルにできない、またはローカルにしないようにしたい場合は、インターフェイスセクションではなく、実装セクションでtypeと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;

Dosomeprocess((PeopleIncluded)は、レコードも認識している必要があります。複数の場所で同じレコードを宣言するのはちょっと悪いです。そのため、Dosomeprocessで使用できるようにする必要があります。ただし、変数はローカルで宣言する方が適切です。

ただし、小さなクラスを作成するのが最善かもしれません。

于 2012-06-30T09:40:36.320 に答える