8

私たちが取り組んでいる Delphi アプリケーションには、関連するオブジェクトの大きな構造があります。これらのオブジェクトのプロパティの一部には、実行時に計算される値があり、より集中的な計算のために結果をキャッシュする方法を探しています。私が使用するアプローチは、最初に計算されたときにプライベートメンバーに値を保存することです。以下に短い例を示します。

unit Unit1;

interface

type
  TMyObject = class
  private
    FObject1, FObject2: TMyOtherObject;
    FMyCalculatedValue: Integer;
      function GetMyCalculatedValue: Integer;
  public
    property MyCalculatedValue: Integer read GetMyCalculatedValue;
  end;

implementation

  function TMyObject.GetMyCalculatedValue: Integer;
  begin
    if FMyCalculatedValue = 0 then
    begin
      FMyCalculatedValue :=
        FObject1.OtherCalculatedValue + // This is also calculated
        FObject2.OtherValue;
    end;

    Result := FMyCalculatedValue;
  end;

end.

計算に使用されるオブジェクトが変更され、キャッシュされた値をリセットして再計算する必要があることは珍しくありません。これまでのところ、オブザーバー パターンを使用してこの問題に対処しました。オブジェクトは OnChange イベントを実装して、他のユーザーがサブスクライブし、変更時に通知を受け、キャッシュされた値をリセットできるようにします。このアプローチは機能しますが、いくつかの欠点があります。

  • サブスクリプションを管理するには大量のメモリが必要です。
  • キャッシュされた値が多くのオブジェクト (リストなど) に依存している場合、うまくスケーリングされません。
  • 依存関係はあまり明確ではありません (キャッシュ値が 1 つのプロパティのみに依存している場合でも、他のプロパティが変更されるとリセットされます)。
  • サブスクリプションの管理は、全体的なパフォーマンスに影響を与え、維持するのが困難です (オブジェクトが削除、移動されるなど)。
  • 他の計算値に依存する計算をどのように処理するかが明確ではありません。

最後に質問です。キャッシュされた計算値を実装するための他のアプローチを提案できますか?

4

3 に答える 3

4

オブザーバー パターンを回避したい場合は、ハッシュ アプローチの使用を試みることができます。

アイデアは、引数を「ハッシュ」し、これが状態が保存されている「ハッシュ」と一致するかどうかを確認することです。そうでない場合は、再計算します (したがって、新しいハッシュをキーとして保存します)。

思いついたように聞こえるかもしれませんが、実際には有名なソフトウェアで使用されています。

たとえば、SCons (Makefile の代替) は、タイムスタンプ アプローチに合わせてターゲットを再構築する必要があるかどうかを確認します。

SCons を 1 年以上使用していますが、ターゲットが再構築されていないという問題はまったく検出されていないため、そのハッシュはうまく機能しています。

于 2009-10-08T08:46:16.117 に答える
2

必要な外部オブジェクト値のローカル コピーを保存できます。次に、アクセス ルーチンはローカル コピーを外部値と比較し、変更の再計算のみを行います。

同様に、外部オブジェクトのプロパティにアクセスすると、これらのプロパティの再評価が強制される可能性があるため、システムは自動的に最新の状態に保つ必要がありますが、必要な場合にのみ再計算します。循環依存を回避するための措置を講じる必要があるかどうかはわかりません。

これにより、各オブジェクトに必要なスペースが増えますが、オブザーバー パターンは削除されます。また、ソース パラメータが変更されるたびに計算を実行するのではなく、必要になるまですべての計算を延期します。これがあなたのシステムに関連していることを願っています。

unit Unit1;

interface

type
  TMyObject = class
  private
    FObject1, FObject2: TMyOtherObject;
    FObject1Val, FObject2Val: Integer;
    FMyCalculatedValue: Integer;
      function GetMyCalculatedValue: Integer;
  public
    property MyCalculatedValue: Integer read GetMyCalculatedValue;
  end;

implementation

  function TMyObject.GetMyCalculatedValue: Integer;
  begin
    if (FObject1.OtherCalculatedValue <> FObjectVal1)
    or (FObject2.OtherValue <> FObjectVal2) then
    begin
      FMyCalculatedValue :=
        FObject1.OtherCalculatedValue + // This is also calculated
        FObject2.OtherValue;
      FObjectVal1 := FObject1.OtherCalculatedValue;
      FObjectVal2 := Object2.OtherValue;
    end;

    Result := FMyCalculatedValue;
  end;

end.
于 2009-10-08T10:57:25.370 に答える
1

私の仕事では、相互に依存するキャッシュされた値の無制限の複雑な構造を管理できるDelphi 用の Boldを使用しています。通常、各変数は問題のごく一部しか保持していません。このフレームワークでは、派生属性と呼ばれます。値がデータベースに保存されないために派生します。データベース内の他の派生属性または永続属性に依存するだけです。

このような属性の背後にあるコードは、Delphi でプロシージャとして、またはモデル内の OCL (オブジェクト制約言語) で記述されます。Delphi コードとして記述する場合は、依存する変数をサブスクライブする必要があります。したがって、属性 C が A と B に依存している場合、A または B が変更されるたびに、再計算 C のコードが C の読み取り時に自動的に呼び出されます。したがって、最初に C が読み取られると、A が読み取られ、B も読み取られます (おそらくデータベースから)。A と B が変更されない限り、C を読み取ることができ、非常に高速なパフォーマンスが得られます。複雑な計算の場合、これにより CPU 時間を大幅に節約できます。

欠点と悪いニュースは、Bold が公式にサポートされなくなり、購入することもできないことです。たくさんの人に聞けば手に入ると思いますが、どこからダウンロードできるのかわかりません。2005 年から 2006 年にかけて、Borland から無料でダウンロードできましたが、現在はダウンロードできません。誰かがそれを Unicode に移植する必要があるため、D2009 の準備ができていません。

別のオプションは、 Capable Objectsの dot.net を使用したECOです。ECO は Visual Studio のプラグインです。これは、Bold for Delphi と同じアイデアと作成者を持つサポート対象のフレームワークです。GUI コンポーネントにデータバインディングが使用されるなど、多くの点も改善されています。Bold と ECO はどちらも、モデルをクラス、属性、およびリンクの中心点として使用します。これらは、データベースまたは xml ファイルに永続化できます。ECO の無料版では、モデルは最大 12 クラスを持つことができますが、私が覚えているように、他に制限はありません。

Bold と ECO には、生産性を高め、データベースの技術的な詳細や、場合によっては値をキャッシュする方法ではなく、問題について考えることができる派生属性以上のものが含まれています。これらのフレームワークについてさらに質問がある場合は、大歓迎です!

編集: 実際には、Embarcadero 登録ユーザー向けのBold for Delphi for D7 のダウンロード リンクがありますが、かなり古いものです... D2005、ad D2006 の更新があったことは知っています。

于 2009-10-08T18:11:01.550 に答える