gpt4 book ai didi

arrays - 如果可以估计的话,TList、TObjectList 和普通数组之间的性能差异有多明显?

转载 作者:行者123 更新时间:2023-12-03 14:45:18 24 4
gpt4 key购买 nike

*摘要:

请查看 Delphi 专家的专业评论。特别是对于我来说,我会尝试按照 David 的建议使用旧的 TList/TObjectList,并按照 A.Bouchez 的建议使用硬转换和 TObjectList.List 属性。以后重构的时候我会尝试一下TDynArray。

================================================== =====================

假设我有一个 TAtom 类,如以下代码中所定义。运行时大约有数百数千 TAtom 实例,目前存储在动态数组中。在运行时,我需要对所有现有 TAtom 实例的 TAtom.X/Y/Z 进行简单的 float 学运算,每秒超过 30 次。

现在,我需要添加在运行时添加插入删除 TAtom 实例的功能。看来我的选择是(1)请求一个大数组; (2) 坚持动态数组并手动SetLength; (3)切换到常规TList; (4) 切换到常规TObjectList。

除非有必要,否则我想避免 (1),因为这样我就必须更改很多函数签名。 (2) 看起来也不太好,因为 TList/TObjectList 似乎就是为这个任务而生的。然而,由于使用常规 TList/TObjectList 需要进行类型转换,有人可以评论一下可能的性能影响吗?我的意思是,如果在重写代码之前能够估计性能负担,那就最好了。如果性能明显下降,我可以使用其他技术吗?

此外,我想知道使用TList和TObjectList是否有性能差异?

  TAtom = class
public
ElementZ: Integer;
X, Y, Z: Extended;
other variables: other types;
end;

TAAtom = array of TAtom;

最佳答案

我可以在您的列表中添加另一个选择吗?

如果您没有对 TAtom 中的数据使用任何继承功能,则可以使用记录而不是。每个类实例都需要在内存中分配,用零填充并单独初始化。 Getmem/Freemem总是有成本的,并且内存碎片会增加。

预先分配的动态记录数组将比添加单个类实例更快。并且数据更适合CPU L1/L2 缓存。

对于插入和删除,如果您有大量项目,则此类记录的数组将比 TList 慢,因为将有更多数据需要删除/插入 (TList/TObjectList 都只维护一个指针列表)。为了更快地插入/删除,您最好使用链表。

由于内部通知,TList/TObjectList 机制中存在一些开销。机制 并且 GetItem() 属性可能比直接使用动态数组慢一些(因为范围检查)。

但是有了我们的 TDynArray wrapper ,您可以坚持使用动态数组,并且仍然具有良好的性能、预分配功能和类似 TList 的方法。甚至还有更多可用方法,例如 SaveToStream、Slice、Reverse、使用外部索引排序等...

type
TAtom = record // could be 'packed record' to save memory (but loose perf)
ElementZ: Integer;
X, Y, Z: Extended;
other variables: other types;
// TDynArray also handle complex (e.g. string) types here
end;
TAtoms = array of TAtom;

var Atom: TAtom;
AtomArray: TAtoms;
AtomCount: integer;
Atoms: TDynArray;
begin
Atoms.Init(TypeInfo(TAtoms),AtomArray,@AtomCount);
Atoms.Capacity := 10000; // pre-allocate array = same as SetLength(AtomArray,10000)
for i := 1 to 10000 do begin
A.ElementZ := Random(1000);
A.X := Random;
A.Y := Ramdom;
A.Z := Random;
// set other fields
Atoms.Add(A); // fast adding of A properties
end;
// you have TList-like methods for your dynamic array
Atoms.Delete(500); // delete 500th item
A.ElementZ := 5000;
Atoms.Insert(500,A); // insert A values at 500th index
assert(Atoms.Count=10000);
assert(AtomCount=10000); // same as Atoms.Count
Atoms.Compare := SortDynArrayInteger;
Atoms.Sort; // will sort by 1st Integer value = ElementZ
for i := 1 to Atoms.Count-1 do // or AtomCount-1
// you have still direct access to AtomArray[]
// -> this is even the fastest access to the data
assert(AtomArray[i].ElementZ >=AtomArray[i-1].ElementZ )
Atoms.SaveToStream(aStream); // will also save any string content
Atoms.Reverse; // reverse all items order
Atoms.Clear;
// faster adding will be done with direct access to the dynamic array
Atom.Count := 10000; // allocate memory for 10000 items
for i := 0 to 10000-1 do
with AtomArray[i] do
begin
ElementZ := Random(2000);
X := Random;
Y := Random;
Z := Random;
end;
Atoms.Sort; // TDynArray knows about the data just created
end; // no need to have any try...finally ..Free block

适用于 Delphi 6 至 XE。

随着新版本的 Delphi 支持泛型,您应该更好地朝这个方向发展。

关于arrays - 如果可以估计的话,TList、TObjectList 和普通数组之间的性能差异有多明显?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5352021/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com