Что лучше для производительности? XPathNavigator с XPath против Linq в Xml с запросом? - PullRequest
4 голосов
/ 16 декабря 2011

У меня есть приложение, в котором я использую XPathNavigator для итерации узлов. Работает нормально.

Но я хочу знать, что если я использую LINQ to Xml ....

  1. Какие преимущества (производительность, ремонтопригодность) я получу?

  2. С XPath, LINQ to Xml какая производительность снижается?

Я использую C # .net, VS 2010, и мой .xml среднего размера.

Ответы [ 2 ]

6 голосов
/ 26 мая 2013

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

Если вы выбираете узлы, проходите через эти узлы и читаете некоторые значения атрибутов:

  • XElement.Element работает быстрее, чем XElement.CreateNavigator.Select by приблизительный коэффициент 1,5.
  • XElement.CreateNavigator.Select быстрее чем XPathNavigator. Выберите примерно в 0,5 раза.
  • XPathNavigator.Select выполняется быстрее, чем XElement.XPathSelectElement, приблизительный коэффициент 0,5.

С другой стороны, если вы также читаете значение дочерних узлов каждого узла, становится немного интереснее:

  • XElement.Element работает быстрее, чем XElement.XPathSelectElements, приблизительно в 0,5 раза.
  • XElement.XPathSelectElement работает быстрее, чем XPathNavigator. Выберите примерно в 3 раза.
  • XPathNavigator.Select выполняется быстрее, чем XElement.CreateNavigator.Select с приблизительным коэффициентом 0,5.

Эти выводы основаны на следующем коде:

 [Test]
    public void CompareXPathNavigatorToXPathSelectElement()
    {     
        var max = 100000;

        Stopwatch watch = new Stopwatch();
        watch.Start();

        bool parseChildNodeValues = true;

        ParseUsingXPathNavigatorSelect(max, watch, parseChildNodeValues);
        ParseUsingXElementElements(watch, max, parseChildNodeValues);
        ParseUsingXElementXPathSelect(watch, max, parseChildNodeValues);
        ParseUsingXPathNavigatorFromXElement(watch, max, parseChildNodeValues);
    }

    private static void ParseUsingXPathNavigatorSelect(int max, Stopwatch watch, bool parseChildNodeValues)
    {
        var document = new XPathDocument(@"data\books.xml");
        var navigator = document.CreateNavigator();

        for (var i = 0; i < max; i++)
        {
            var books = navigator.Select("/catalog/book");
            while (books.MoveNext())
            {
                var location = books.Current;
                var book = new Book();
                book.Id = location.GetAttribute("id", "");

                if (!parseChildNodeValues) continue;

                book.Title = location.SelectSingleNode("title").Value;
                book.Genre = location.SelectSingleNode("genre").Value;
                book.Price = location.SelectSingleNode("price").Value;
                book.PublishDate = location.SelectSingleNode("publish_date").Value;
                book.Author = location.SelectSingleNode("author").Value;
            }
        }

        watch.Stop();
        Console.WriteLine("Time using XPathNavigator.Select = " + watch.ElapsedMilliseconds);
    }

    private static void ParseUsingXElementElements(Stopwatch watch, int max, bool parseChildNodeValues)
    {
        watch.Restart();
        var element = XElement.Load(@"data\books.xml");

        for (var i = 0; i < max; i++)
        {
            var books = element.Elements("book");
            foreach (var xElement in books)
            {
                var book = new Book();
                book.Id = xElement.Attribute("id").Value;

                if (!parseChildNodeValues) continue;

                book.Title = xElement.Element("title").Value;
                book.Genre = xElement.Element("genre").Value;
                book.Price = xElement.Element("price").Value;
                book.PublishDate = xElement.Element("publish_date").Value;
                book.Author = xElement.Element("author").Value;
            }
        }

        watch.Stop();
        Console.WriteLine("Time using XElement.Elements = " + watch.ElapsedMilliseconds);
    }

    private static void ParseUsingXElementXPathSelect(Stopwatch watch, int max, bool parseChildNodeValues)
    {
        XElement element;
        watch.Restart();
        element = XElement.Load(@"data\books.xml");

        for (var i = 0; i < max; i++)
        {
            var books = element.XPathSelectElements("book");
            foreach (var xElement in books)
            {
                var book = new Book();
                book.Id = xElement.Attribute("id").Value;

                if (!parseChildNodeValues) continue;

                book.Title = xElement.Element("title").Value;
                book.Genre = xElement.Element("genre").Value;
                book.Price = xElement.Element("price").Value;
                book.PublishDate = xElement.Element("publish_date").Value;
                book.Author = xElement.Element("author").Value;
            }
        }

        watch.Stop();
        Console.WriteLine("Time using XElement.XpathSelectElement = " + watch.ElapsedMilliseconds);
    }

    private static void ParseUsingXPathNavigatorFromXElement(Stopwatch watch, int max, bool parseChildNodeValues)
    {
        XElement element;
        watch.Restart();
        element = XElement.Load(@"data\books.xml");

        for (var i = 0; i < max; i++)
        {
            // now we can use an XPath expression
            var books = element.CreateNavigator().Select("book");

            while (books.MoveNext())
            {
                var location = books.Current;
                var book = new Book();
                book.Id = location.GetAttribute("id", "");

                if (!parseChildNodeValues) continue;

                book.Title = location.SelectSingleNode("title").Value;
                book.Genre = location.SelectSingleNode("genre").Value;
                book.Price = location.SelectSingleNode("price").Value;
                book.PublishDate = location.SelectSingleNode("publish_date").Value;
                book.Author = location.SelectSingleNode("author").Value;
            }
        }

        watch.Stop();
        Console.WriteLine("Time using XElement.Createnavigator.Select = " + watch.ElapsedMilliseconds);
    }

с books.xml, загруженным с здесь

В целом, похоже, что API синтаксического анализа XElement, за исключением расширений XPath, обеспечивает лучшую производительность, а также более прост в использовании, если ваш документ несколько плоский. Если у вас есть глубоко вложенные структуры, где вы должны сделать что-то вроде

XElement.Element("book").Element("author").Element("firstname").SomethingElse()

тогда XElement.XPathSelectElement может обеспечить лучший компромисс между производительностью и удобством сопровождения кода.

3 голосов
/ 16 декабря 2011

Ну, XPathNavigator обычно будет быстрее, чем Linq to XML запросов. Но всегда есть «но».

Linq to XML определенно сделает ваш код более читабельным и понятным. Проще (по крайней мере для меня) прочитать запрос linq, а затем проанализировать XPath. Также - вы получите intellisense при написании запроса, который поможет сделать ваш код правильным. Linq to XML также дает вам возможность легко изменять данные, если это то, что вам нужно. XPathNavigator предоставляет доступ только для чтения.

С другой стороны, если вам действительно нужна максимальная производительность, XPathNavigator - это, вероятно, путь. Это просто зависит от вашего текущего сценария и того, что вы пытаетесь достичь. Если производительность не является проблемой (файл XML довольно мал, вы не будете делать много запросов к этому файлу и т. Д.), Вы легко можете использовать Linq to XML. В противном случае придерживайтесь близко к XPathNavigator.

...