VB. net чтение большого XML файла параллельно - PullRequest
1 голос
/ 07 апреля 2020

История: у меня есть большой XML файл размером более 70 ГБ, который мне нужно анализировать в базе данных один раз в неделю. В настоящее время у меня есть рабочий синтаксический анализатор в VB. net с использованием XmlReader. В настоящее время я достигаю максимума в 5.000 узлов / с c и с> 10.000.000 узлов и растущими, это требует времени для завершения. Программа работает на моем собственном сервере в гараже с обычным SSD. Я предположил, что ограничивающим фактором был SSD, поэтому недавно я перешел на Samsung EVO 970 M.2 SSD с увеличенной в 6 раз скоростью чтения / записи. Проблема в том, что я не увидел заметного увеличения производительности. Оглядываясь назад, вероятно, очевидно, что узкое место где-то еще ..

Идея: я начал расследование. Я реализовал 2 отдельных потока, каждый из которых считывал файл с начала, с интервалом в несколько секунд. Каждый поток все еще считывал и обрабатывал около 5000 узлов / сек c, поэтому теперь я эффективно обрабатывал 10.000 узлов / сек c Однако проблема заключалась в том, что я дважды анализировал каждый узел, что отчасти устранило цель. Следующая идея была для одного потока, чтобы прочитать + обработать данные с самого начала. Второй поток также считывает данные с начала файла, однако этот поток просто пропускает первую половину файла, прежде чем он начнет обработку данных. Используя XMLReader.ReadToNextSibling (), я смог «пропустить» 6,250,000 узлов со скоростью 10000 узлов / сек c. По сути, это означает, что первый поток обработал бы около 3,125,000 узлов к тому времени, когда второй поток завершит «пропуск» и начнет анализировать с 6,250,000 узлов. На этом этапе между 6,875,000 узлов будет разбито. 2 потока и парсер будет с этого момента обрабатывать около 10.000 узлов / сек c. По сути, я хотел бы увеличить потоки, пока не достигну другого узкого места. Этот подход очень примитивен и «тратит» много времени на чтение и пропуск тех же узлов. Я попытался XmlReaderSettings.LineNumberOffset, однако я не мог заставить это работать, и это всегда, казалось, читало с начала независимо от смещения.

Dim settings = New Xml.XmlReaderSettings()
settings.LineNumberOffset = 100000

Dim XMLReader = Xml.XmlReader.Create("C:\largexml.xml", settings)

Вопрос: Любые идеи параллельного чтения больших файлов XML и возможные узкие места или оптимизации. Есть ли более быстрый способ "пропустить" n элементов, чем использовать ReadToNextSibling, как это?

Dim Count As Integer = 0
While Count < 5000000
   XMLReader.ReadToNextSibling("ns")
   Count += 1
End While

Я провел некоторые расчеты текущего решения "пропустить", и, поскольку мне приходится читать те же данные в каждый поток, то бонус скорости асимптотически c до + 50% ускорения. Вот график на случай, если у кого-то возникнет такая же проблема, и он рассматривает подобное наивное решение. Вот ожидаемое увеличение производительности / поток.

enter image description here

1 Ответ

0 голосов
/ 08 апреля 2020

Проверьте, быстрее ли следующий код. XElement.ReadFrom () читает брат и сестру, поэтому он читает элемент только один раз. Проверьте в диспетчере задач использование памяти при выполнении кода. Если у вас недостаточно памяти, то используется место подкачки на диске, что может реально замедлить работу приложения.

Imports System.Xml
Imports System.Xml.Linq
Module Module1
    Const FILENAME As String = "C:\largexml.xml"
    Sub Main()
        Dim reader As XmlReader = XmlReader.Create(FILENAME)
        While Not reader.EOF
            If reader.Name <> "ns" Then
                reader.ReadToFollowing("ns")
            End If
            If Not reader.EOF Then
                Dim ns As XElement = XElement.ReadFrom(reader)
            End If
        End While

    End Sub

End Module
...