在C#中迭代大型集合:需要很长时间

时间:2012-07-02 18:38:20

标签: c# wpf collections iteration

我最近开始使用WPF应用程序。我将它连接到BaseX(基于XML)的数据库,并从中检索了大约一百万个条目。我想迭代条目,为每个条目计算一些东西,然后将其写回数据库:

IEnumerable<Result> resultSet = baseXClient.Query("...", "database");
foreach (Result result in resultSet) 
{
    ...
}

问题:从未到达foreach的内部。 Query()方法返回得非常快,但是当到达foreach时,C#似乎对集合进行了SOMETHING,代码不会持续很长时间(至少10分钟,永远不会让它再运行)。 这里发生了什么? 我试图限制检索的项目数量。检索100.000结果时,会发生相同的事情,但代码会在大约10-20秒后继续。在检索完整的一百万个结果时,C#似乎永远被卡住了......

有什么想法吗? 问候

编辑:为什么会发生这种情况 正如你们中的一些人所指出的,这种行为的原因似乎是查询实际上仅在调用Enumerable中的Enumerator上的MoveNext()时进行评估。我的数据库似乎无法一次返回一个值,而是一次返回整个一百万个数据集。我将尝试切换到另一个数据库(Apache Lucene,如果可能的话,因为它具有良好的全文搜索支持)并编辑此帖子以告知您是否更改了任何内容。
PS:是的,我知道有一百万个结果很多。这不是用于实时使用,它只是准备数据的一个步骤。虽然我没想到代码会在几秒钟内运行,但我仍然对数据库中的性能不佳感到惊讶。

编辑:解决方案所以我将XML数据库迁移到了Apache Lucine。奇迹般有效!当然Lucine是一个基于文本的数据库,不适合每个用例,但对我来说它创造了奇迹。可以在几秒钟内迭代超过一百万个条目,每个循环获取一个条目 - 工作得非常好!

5 个答案:

答案 0 :(得分:5)

让我猜一下 - 你在创建rsultSet时没有加载数据,但是当它第一次被访问(延迟执行),加载一百万个条目时,你只需要花很多时间将它们反序列化到内存中。

欢迎使用XML数据库的低效率。

答案 1 :(得分:3)

一百万的东西都很多......所以任何获得那么多项目的操作都需要花费大量的时间。它看起来像你使用的库不会延迟检索项目,直到它是绝对必要的 - 所以你看到所有项目隐藏在“foreach”声明背后的影响。

会发生什么:

“foreach”不是单个操作,而是对IEnumerable和IEnumerator的几次调用:IEnumerable.GetEnumerator,重复调用IEnumerator.MoveNext。

第一次调用GetEnumerator可以通过延迟执行(最常见的LINQ查询编写方式)或立即执行(这似乎是您的集合的情况)来实现。

调用MoveNext也可以触发立即执行整个查询,即使您只询问单个项目或每个调用只能获得单个项目。即大多数LINQ查询只从迭代器中获取一个下一项。

答案 2 :(得分:2)

这里的答案都指出了你对foreach(延迟执行)感知问题的原因,而不是可能的解决方案。我不确定这个数据库是否支持它,但是一个解决方案可能是尝试以较小的批量分页结果,而不是一次获取整个数据块。

另一种方法是编写一个执行必要计算的数据库查询,这样您的数据库就不需要在任何地方发送100万条记录。 (同样,不确定这个数据库是否支持)

答案 3 :(得分:0)

要强制在foreach之前计算查询,请调用resultSet上的ToList函数。 (如果问题是数据库永远存在,不会解决您的问题)

答案 4 :(得分:-1)

您是否尝试过更传统的for循环来查看是否可行?

IEnumerable<Result> resultSet = baseXClient.Query("...", "database");
for (int x =0; x < resultSet.Count; x++)
{
    Result result = resultSet[x];
    ...
}