Delphi 缓存计算值的方法
在我们正在处理的Delphi应用程序中,我们有一个相关对象的大结构。这些对象的某些属性具有在运行时计算的值,我正在寻找一种方法来缓存结果,以便进行更密集的计算。我使用的一种方法是在第一次计算时将值保存在私有成员中。下面是一个简短的例子:Delphi 缓存计算值的方法,delphi,oop,caching,delphi-2006,Delphi,Oop,Caching,Delphi 2006,在我们正在处理的Delphi应用程序中,我们有一个相关对象的大结构。这些对象的某些属性具有在运行时计算的值,我正在寻找一种方法来缓存结果,以便进行更密集的计算。我使用的一种方法是在第一次计算时将值保存在私有成员中。下面是一个简短的例子: unit Unit1; interface type TMyObject = class private FObject1, FObject2: TMyOtherObject; FMyCalculatedValue: Integer;
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事件,以便其他人可以订阅、在更改和重置缓存值时得到通知。这种方法可行,但也有一些缺点:
- 管理订阅需要大量内存
- 当缓存的值依赖于许多对象(例如列表)时,它的伸缩性不好
- 依赖关系不是很具体(即使缓存值仅依赖于一个属性,当其他属性更改时也会重置)
- 管理订阅会影响总体性能,并且很难维护(对象被删除、移动等)
- 不清楚如何根据其他计算值处理计算
最后一个问题是:您能推荐其他实现缓存计算值的方法吗?如果您想避免观察者模式,您可以尝试使用散列方法 这样做的想法是对参数进行“散列”,并检查其是否与保存状态的“散列”匹配。如果没有,则重新计算(从而将新哈希保存为密钥) 我知道我让它听起来像是我刚刚考虑过的,但事实上它是由知名软件使用的 例如,(Makefile alternative)检查目标是否需要重新构建,最好是使用时间戳方法
我们已经使用SCON一年多了,我们从未检测到任何未重建的目标问题,所以它们的哈希工作得很好 您可以存储所需的外部对象值的本地副本。然后,访问例程将本地副本与外部值进行比较,并且仅对更改进行重新计算 访问外部对象属性同样会强制对这些属性进行可能的重新评估,因此系统应自动保持自身最新,但仅在需要时重新计算。我不知道您是否需要采取措施来避免循环依赖 这会增加每个对象所需的空间量,但会删除观察者模式。它还会将所有计算推迟到需要时,而不是在每次源参数更改时执行计算。我希望这与您的系统相关
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.
在我的工作中,我使用Delphi的粗体,它可以管理无限的复杂的缓存值结构,这些缓存值相互依赖。通常每个变量只包含问题的一小部分。在这个框架中,它被称为派生属性。派生因为该值不保存在数据库中,所以它只依赖于数据库中的其他派生属性或持久属性 此类属性背后的代码是作为过程或模型中的OCL(对象约束语言)在Delphi中编写的。如果您将其作为Delphi代码编写,则必须订阅依赖的变量。因此,如果属性C依赖于A和B,那么每当A或B更改recalc的代码时,在读取C时会自动调用C。因此,第一次读取C时,A和B也会被读取(可能是从数据库中读取)。只要A和B不改变,就可以读取C并获得非常快的性能。对于复杂的计算,这可以节省相当多的CPU时间 缺点和坏消息是,政府不再支持Bold,你也不能买它。如果你问足够多的人,我想你可以得到,但我不知道你可以从哪里下载。大约在2005-2006年,它可以从Borland免费下载,但现在不再是了。 它还没有为D2009做好准备,因为有人必须将其移植到Unicode 另一个选项是使用来自的.net。ECO是Visual Studio中的一个插件。这是一个受支持的框架,与Delphi的Bold具有相同的想法和作者。许多方面也得到了改进,例如GUI组件使用了数据绑定。Bold和ECO都使用模型作为具有类、属性和链接的中心点。这些可以保存在数据库或xml文件中。在ECO的免费版本中,模型最多可以有12个类,但我记得没有其他限制 Bold和ECO包含的不仅仅是派生属性,它们使您的工作效率更高,并允许您思考问题,而不是数据库的技术细节,或者在您的情况下如何缓存值。欢迎您提出更多关于这些框架的问题 编辑:
实际上有一个德尔福黑体版D7的下载,相当老了。。。我知道D2005,ad D2006有更新。即使标记为“delphi”,我也很想知道是否开发了特定的模式。我添加了delphi标记,以便将建议限制为静态类型,不是垃圾收集语言。为了安全起见,我还将在执行计算之前验证是否分配了fObject1和fObject2。@skamradt:同意。我假设这个问题忽略了输入验证/错误检测,以保持示例代码的简单。只需确保计算哈希(或您选择的任何方法)比重新计算(明显)快。是的,我没有指出这一点,因为它听起来很明显,但与优化一样。。。你真的必须测量。一般来说,模型驱动的框架,特别是“Bold for Delphi”听起来非常有趣。非常感谢。事实上,我在我的一个硬盘上发现了D2006的粗体(我认为这是最新的公开版本),所以如果你是int