【发布时间】:2020-07-20 01:36:56
【问题描述】:
故事: 我有一个大约 70+ GB 的大型 XML 文件,我需要每周解析一次我的数据库。目前我在 vb.net 中有一个使用 XmlReader 的工作解析器。我目前以大约 5.000 个节点/秒的速度达到最大值,并且节点数 >10.000.000 并且还在增加,这需要一段时间才能完成。该程序使用普通 SSD 在车库中我自己的服务器上运行。我认为限制因素是 SSD,所以我最近升级到了三星 EVO 970 M.2 SSD,读/写速度提高了 6 倍。问题是我没有看到任何明显的性能提升。回过头来看,很明显瓶颈在其他地方..
想法: 我开始调查。我实现了 2 个单独的线程,每个线程从头开始读取文件,相隔几秒钟。每个线程仍然读取和处理大约 5.000 个节点/秒,因此我现在处理 10.000 个节点/秒非常有效。但是问题是我对每个节点进行了两次解析,这消除了目的。下一个想法是让一个线程从一开始就读取+处理数据。第二个线程也会从文件的开头读取,但是这个线程会在开始处理数据之前跳过文件的前半部分。使用 XMLReader.ReadToNextSibling() 我能够以 10.000 个节点/秒的速度“跳过”6.250.000 个节点。这实质上意味着,当第二个线程完成“跳过”并从 6.250.000 个节点开始解析时,第一个线程将处理大约 3.125.000 个节点。此时,将有大约 6.875.000 个节点在2 个线程和解析器将从此时开始处理大约 10.000 个节点/秒。本质上,我想增加线程,直到遇到另一个瓶颈。这种方法非常原始,并且“浪费”了大量时间阅读和跳过相同的节点。我尝试了 XmlReaderSettings.LineNumberOffset,但是我无法让它工作,而且无论偏移量如何,它似乎总是从头开始读取。
Dim settings = New Xml.XmlReaderSettings()
settings.LineNumberOffset = 100000
Dim XMLReader = Xml.XmlReader.Create("C:\largexml.xml", settings)
问题: 关于并行读取大型 XML 文件以及可能的瓶颈或优化的任何想法。有没有比这样使用 ReadToNextSibling 更快的“跳过”n 个元素的方法?
Dim Count As Integer = 0
While Count < 5000000
XMLReader.ReadToNextSibling("ns")
Count += 1
End While
我已经对当前的“跳过”解决方案进行了一些计算,并且由于我必须在每个线程中读取相同的数据,因此速度奖励与 +50% 的速度提升是渐近的。这是图表,以防有人遇到同样的问题并正在考虑类似的幼稚解决方案。这是预期的性能提升/线程。
【问题讨论】:
-
那么节点是否等同于数据库记录?您是否正在读取节点并将结果直接发送到数据库?如何发送记录(顺序插入或批量复制)?你用的是什么数据库?
-
这里所有的测试都没有解析到数据库。在生产中,我将 XML 文件中的 5.000 个节点保存在 DataTable 中,然后将其批量插入 MSSQL 服务器。然而,这几乎是立即发生的,在我当前的测试中,我只需将 5.000 行插入到我的应用程序中的 DataTable 中,然后在不推送到数据库的情况下清除它。所以目前的瓶颈不在于数据库。
-
您是否尝试过将StreamReader's buffer size 从默认的 128 个字符增加到 1024 个字符,看看是否有帮助?您也可以尝试增加底层流的缓冲区。
-
@TnTinMn 这不是默认值,而是允许的最小值。 StreamReader 缓冲区的默认值为
1024字节(文件流缓冲区为4096),XMLReader 为4096,或8192,具体取决于流大小。 -
@Jimi,感谢您提示我检查。看起来我应该检查源代码而不是我引用的文档。在任何情况下,为 XMLReader 提供 StreamReader 可能仍然会有所帮助。创建具有较大缓冲区大小的。因此,而不是您所说的 8192 最大默认值,也许使用该值的两倍。他们赋予我们这种能力是有原因的。