如何对大规模集合进行序列化

6

我正在处理一个系统,其中包含超过500万个列表和字典,每个项目通常是一个带有高达90个原始属性的平面dto。使用protobuf-net将这些集合持久化到磁盘以实现弹性和后续处理。

毫不奇怪,在处理和序列化期间我们会遇到LOH问题。

我们可以通过使用ConcurrentBag等来避免在处理期间遇到LOH问题,但是在序列化时仍然会存在问题。

目前,集合中的项目被分批成1000个一组并行地序列化到内存流中。 然后将每个字节数组放入并发队列中,以便稍后写入文件流。

虽然我理解了这样做的目的,但它似乎过于复杂。感觉protobuf本身应该有处理大型集合而不使用LOH的解决方案。

我希望我犯了低级错误-可能有一些设置我忽略了。否则,我将尝试编写自定义二进制读写器。

我应该指出,我们正在使用4.0版本,计划很快升级到4.5,但我们意识到即使有GC改进,我们也无法解决这个问题。

任何帮助都将不胜感激。


你对于有许多短寿命的LOH对象有什么问题? - xanatos
1
@Joe 这几乎可以确定是子对象输出缓冲。在大多数情况下,这可以通过使用"group"数据格式来修复。你有一个具体的模型我可以看看吗? - Marc Gravell
很遗憾我不能展示确切的模型,但我已经在 github 上放了一个小测试应用。没有太多可以看到的东西——简单的扁平模型(虽然没有使用“组”格式)——我将整个包序列化。 - Joe
抱歉,在示例程序中,您需要重复选择64位上的选项BDX才能获得OOM。但是,在异常之前,如果您打开perfmon并监视LOH,则可以看到问题:一旦序列化袋子,堆就会迅速增长,清除袋子不会压缩内存。 - Joe
我刚刚注意到,虽然ConcurrentBag在写入期间避免了问题,但如果您枚举整个包,则堆会急剧增长。这表明这根本不是protobuf-net的问题。 - Joe
显示剩余5条评论
1个回答

0

将数据写入磁盘,不要使用内存流。

使用StreamReader进行读取,这样您就不必在内存中保留大量数据。如果需要一次性加载所有数据以进行处理,则可以通过将它们存储在临时表中在SQL服务器中执行。

内存不是存储大量数据的地方。


那么您的建议是,为了处理他们的数值分析数据集(从描述听起来是这样),他们应该在SQL服务器中进行操作并面临跨网络问题,还是将其存储在磁盘上以增加I/O时间? - Tetsujin no Oni
将数据存储在SQL服务器中并进行所有分析,然后只需获取结果是最佳解决方案。但是,如果您的数据最初未存储在SQL中,则最好有一个过程将数据存储在SQL服务器中,另一个过程处理它并返回结果。您能告诉我们您的数据来自哪里吗? - sino
2
如果数据不具备关联性,我认为SQL Server不是一个好的存储和处理方案。 - Tetsujin no Oni
SQL Server适用于各种类型的数据,即使只有字符串。 - sino
1
一个拥有90个属性的平面DTO并不适合SQL Server。关系型数据库通常非常适合它们擅长的事情。声称设计错误,因为它没有SQL Server组件,在我们对Joe正在工作的设计空间了解的信息量如此之少的情况下,这是相当激进的。 - Tetsujin no Oni
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接