Выполнение тестов C # на производительность кода

Недавно я работал над проектом, в котором мне нужно было проанализировать XML-файлы размером от 5 до 20 МБ. Производительность была критически важна для проекта, поэтому я хотел убедиться, что проанализирую эти файлы как можно быстрее.

Мне известны два класса C # для синтаксического анализа XML: XmlReader и XmlDocument. Основываясь на моем понимании этих двух классов, XmlReader должен работать быстрее в моем сценарии, потому что он читает XML-документ только один раз, никогда не сохраняя в памяти больше, чем текущий узел. Напротив, XmlDocument сохраняет весь XML-файл в памяти, что снижает производительность.

Не зная наверняка, какой метод мне следует использовать, я решил написать быстрый тест производительности, чтобы измерить фактические результаты этих двух классов.

Данные

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

Для своего теста я решил использовать дамп пользовательских данных Photography Stack Exchange в качестве образца файла, поскольку он имитирует структуру и размер файла данных одного из моих реальных проектов. Дампы данных Stack Exchange - отличные образцы наборов данных, потому что они включают реальные данные и выпускаются под лицензией Creative Commons.

Тест

Код C # для моего теста можно полностью найти на GitHub.

В своем тесте я создал два метода для извлечения одних и тех же точных данных из XML; один из методов использовался XmlReader, а другой XmlDocument.

В первом тесте используется XmlReader. Объект XmlReader сохраняет в памяти только один узел за раз, поэтому для чтения всего документа нам нужно использоватьwhile(reader.Read()), чтобы зациклить все узлы. Внутри цикла мы проверяем, является ли каждый узел тем элементом, который мы ищем, и если да, то анализируем необходимые данные:

С другой стороны, код для XmlDocument намного проще: мы загружаем весь XML-файл в память, а затем пишем LINQ-запрос, чтобы найти интересующие элементы:

После написания этих двух методов и подтверждения того, что они возвращают одинаковые точные результаты, пришло время сопоставить их друг с другом. Я написал метод, позволяющий запускать каждый из двух моих методов синтаксического анализа более 50 раз и брать среднее время выполнения каждого из них, чтобы исключить любые выбросы данных:

Результаты и выводы.

Переходя к делу, в моем тесте XmlReader показал себя быстрее:

Значит ли разница в скорости ~ 0,14 секунды? В моем случае это так, потому что я буду анализировать гораздо больше элементов и файлов десятки раз в день. По моим оценкам, после выполнения математических расчетов я сэкономлю 45–60 секунд на синтаксическом анализе для каждого набора файлов XML, что очень много для системы, работающей почти в реальном времени.

Пришел бы я к такому же выводу, если бы молниеносная скорость не была одним из моих требований? Нет, я бы, вероятно, пошел по пути XmlDocument, потому что код намного чище и, следовательно, его легче поддерживать.

А если бы мои файлы XML были размером 50, 500 или 5 ГБ? Я бы, вероятно, все еще использовал XmlReader в этот момент, потому что попытка сохранить 5 ГБ данных в памяти будет не очень хорошо.

А как насчет сценария, когда мне нужно вернуться назад в моем XML-документе - это может быть тот случай, когда я бы использовал XmlDocument, потому что с этим классом удобнее перемещаться вперед и назад. Однако гибридный подход может быть моим лучшим вариантом, если данные позволяют это: если я могу использовать XmlReader, чтобы быстро просмотреть большую часть моего контента, а затем загрузить только определенные дочерние деревья элементов в XmlDocument для облегчения обратного / прямого обхода, тогда это Казалось бы, идеальный сценарий.

Короче говоря, в моем сценарии XmlReader был быстрее, чем XmlDocumet. Единственный способ прийти к такому выводу - это провести несколько реальных тестов и измерить данные о производительности.

Итак, следует ли вам использовать XmlReader или XmlDocument в вашем следующем проекте? Ответ в зависимости от обстоятельств.