我有一个可能需要处理数十亿个对象的应用程序。每个对象属于TRange类类型。这些范围是在算法的不同部分创建的,这取决于某些条件和其他对象属性。因此,如果您有100个项目,则无法在不创建所有先前对象的情况下直接创建第100个对象。如果我创建所有(数十亿)对象并添加到集合中,系统将抛出Outofmemory错误。现在我想迭代遍历每个对象主要有两个目的:
如何在不提高Outofmemory的情况下为这些对象有效地创建迭代器?
我通过将函数指针传递给算法函数来处理第一种情况。例如:
procedure createRanges(aProc: TRangeProc);//aProc is a pointer to function that takes a //TRange
var range: TRange;
rangerec: TRangeRec;
begin
range:=TRange.Create;
try
while canCreateRange do begin//certain conditions needed to create a range
rangerec := ReturnRangeRec;
range.Update(rangerec);//don't create new, use the same object.
if Assigned(aProc) then aProc(range);
end;
finally
range.Free;
end;
end;
但是这种方法的问题在于,要添加一个新功能,比如检索前面提到的Total权重,要么我必须复制算法函数,要么传递一个可选的out参数。请提出一些想法。
提前谢谢大家 普拉迪普
答案 0 :(得分:8)
对于如此大量的数据,您只需要将一部分数据存储在内存中。其他数据应序列化到硬盘驱动器。我解决了这样一个问题:
这样记录是透明的。您总是像访问内存一样访问它们,但它们可能首先从硬盘驱动器加载。它工作得很好。顺便说一句,RAM以非常类似的方式工作,因此它只保存硬盘上所有数据的某个子集。这是你的工作集。
我没有发布任何代码,因为它超出了问题本身的范围,只会混淆。
答案 1 :(得分:1)
看看TgsStream64。该类可以通过文件映射处理大量数据。
http://code.google.com/p/gedemin/source/browse/trunk/Gedemin/Common/gsMMFStream.pas
答案 2 :(得分:1)
但是这种方法的问题在于,要添加一个新功能,比如检索前面提到的Total权重,要么我必须复制算法函数,要么传递一个可选的out参数。
通常这样做:你编写一个枚举函数(就像你做的那样),它接收一个回调函数指针(你也这样做)和一个无类型指针(“数据:指针”)。您定义一个回调函数,使第一个参数与同一个无类型指针相同:
TRangeProc = procedure(Data: pointer; range: TRange);
procedure enumRanges(aProc: TRangeProc; Data: pointer);
begin
{for each range}
aProc(range, Data);
end;
然后,如果你想对所有范围求和,你可以这样做:
TSumRecord = record
Sum: int64;
end;
PSumRecord = ^TSumRecord;
procedure SumProc(SumRecord: PSumRecord; range: TRange);
begin
SumRecord.Sum := SumRecord.Sum + range.Value;
end;
function SumRanges(): int64;
var SumRec: TSumRecord;
begin
SumRec.Sum := 0;
enumRanges(TRangeProc(SumProc), @SumRec);
Result := SumRec.Sum;
end;
无论如何,如果你需要创造数十亿的任何东西你可能做错了(除非你是一个科学家,建模一些非常大规模和详细的东西)。如果你需要在每次需要其中之一时创建数十亿的东西,那就更是如此了。这永远不会好。试着考虑替代解决方案。
答案 3 :(得分:0)
“Runner”有一个很好的答案如何处理这个!
但我想知道你是否可以快速修复:制作较小的TRange对象。 也许你有一个伟大的祖先?你能看一下TRange对象的实例大小吗? 也许你最好使用打包记录?
答案 4 :(得分:0)
这部分:
结果,如果你有100件物品, 你无法直接创造第100个 对象没有创建所有先前的 对象。
听起来有点像计算Fibonacci。您可以重用一些TRange对象而不是创建冗余副本吗? Here是一篇描述这种方法的C ++文章 - 它通过将已计算的中间结果存储在哈希映射中来工作。
答案 5 :(得分:0)
可以处理数十亿个对象,但应尽可能避免使用它。只有在绝对必须...的情况下才这样做 我曾经创建过一个需要能够处理大量数据的系统。为此,我使我的对象“可流动”,以便我可以将它们读/写到磁盘。围绕它的较大类用于决定何时将对象保存到磁盘并从内存中删除。基本上,当我调用一个对象时,这个类会检查它是否已加载。如果没有,它将再次从磁盘重新创建对象,将其放在堆栈顶部,然后将底部对象从此堆栈移动/写入磁盘。结果,我的堆栈具有固定(最大)的大小。它允许我使用无限量的物体,也具有合理的良好性能 不幸的是,我没有那个代码了。我大约7年前为一位前雇主写过它。我知道你需要为流支持编写一些代码,还需要为堆栈控制器编写更多代码来维护所有这些对象。但从技术上讲,它可以让你创建无限数量的对象,因为你正在为磁盘空间交换RAM内存。