【发布时间】:2014-10-29 12:16:24
【问题描述】:
我正在运行一个 DB 查询,它返回大量特征(大约 100000 个)。因为我遇到了上述异常,所以我尝试将查询拆分为几个子查询。但是因此所有这些子查询的结果都被写入了方法列表,因此我仍然遇到了同样的异常。
所以我想知道是否可以在每个子查询通过循环其元素并返回每一个元素完成后使用yield return。
在检索到这些特性之后,我必须为它们中的每一个创建一些新的自定义对象,所以我想知道在这种情况下使用 yield return 是否会节省内存。
也许下面的内容会更清楚一点:
foreach (var chunk in IDs.chunk(500))
{
List<ComplexObject> result = new List<ComplexObject>():
// ...
// make a (sub-)query on every chunk to retrieve 500 objects at once
// ..
// now we have up to 500 ComplexObjects within result
foreach (var parcel in result)
{
yield return parcel;
parcel.Release(); // release COM-object
}
}
其中chunk 是 500 个元素 (ID) 的(子)集合。
之后,我在foreach 中循环从该方法检索到的结果,并从中创建自定义对象。
编辑:我还可以逐个查询和处理每个ComplexObject,实际上这比检索一堆比如说 500 个元素要慢得多,因为 MetaData 只需检索一次,而不是为每个单个对象检索(还有更多原因,但这个最方便)。
【问题讨论】:
-
这些是 COM 对象,但数据是从数据库中检索的?这个方法的调用者是否需要一次拥有所有这些,或者调用者可以一个一个地处理项目?为什么要“一次”检索 500 个对象?
-
是的,调用者可能会一个一个地使用它们,而不是一次性使用它们。在进行查询时,我有一个接受 ID 集合并在数组中检索其所有对应的
ComplexObjects的方法,所以实际上result将是一个数组而不是一个列表,但我想这没什么区别. -
但是db查询部分长什么样子呢?那是需要更改的实际位置(该方法的结果需要是
IEnumerable<ComplexObject>)。 -
实际查询在黑盒中(至少对我而言)并且确实返回了一个数组。但是因此 500 个元素是一个小集合,我想一次收集 500 个元素(使用提到的查询),然后循环每个元素并直接将其发送给调用者,而不是等到所有块都处理完毕。
-
“小型收藏”是一个相对术语。如果这些对象中的每一个都消耗 2MB 的内存,那么您说的是 1GB 的 RAM。 “黑匣子(至少对我而言)”是什么意思?您是否有可以修改的代码?您可以将块大小设置为1吗?因为这会有效地将其转化为每个实例的“创建过程释放”操作。
标签: c# out-of-memory yield-return