XPath.evaluate производительность замедляется (абсурдно) при нескольких вызовах

Я пытаюсь использовать пакет javax.xml.xpath для запуска выражений XPath в документе с несколькими пространствами имен, и у меня проблемы с производительностью.

Мой тестовый документ взят из реального производственного примера. Это около 600к xml. Документ представляет собой довольно сложный канал Atom.

Я понимаю, что то, что я делаю с XPath, можно обойтись без него. Тем не менее, та же реализация на других, значительно более слабых платформах работает до абсурда лучше. Прямо сейчас перестройка моей системы, чтобы не использовать XPath, выходит за рамки того, что я могу сделать в то время, которое у меня есть.

Мой тестовый код выглядит примерно так:



void testXPathPerformance()
{
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);
    DocumentBuilder builder = factory.newDocumentBuilder();

    Document doc = builder.parse(loadTestDocument());

    XPathFactory xpf = XPathFactory.newInstance();
    XPath xp = xpf.newXPath();

    NamespaceContext names = loadTestNamespaces();
    //there are 12 namespaces in names.  In this example code, I'm using
    //'samplens' instead of the actual namespaces that my application uses
    //for simplicity.  In my real code, the queries are different text, but
    //precisely the same complexity.

    xp.setNamespaceContext(names);

    NodeList nodes = (NodeList) xp.evaluate("/atom:feed/atom:entry",
                     doc.getDocumentElement(), XPathConstants.NODESET);


    for(int i=0;i<nodes.getLength();i++)
    {
        printTimestamp(1);
        xp.evaluate("atom:id/text()", nodes.item(i));
        printTimestamp(2);
        xp.evaluate("samplens:fieldA/text()", nodes.item(i));
        printTimestamp(3);
        xp.evaluate("atom:author/atom:uri/text()", nodes.item(i));
        printTimestamp(4);
        xp.evaluate("samplens:fieldA/samplens:fieldB/&at;attrC", nodes.item(i));
        printTimestamp(5);

        //etc.  My real example has 10 of these xp.evaluate lines

     }
}

Когда я запускаю Nexus One (не в отладчике, а с подключенным USB), при первом прохождении цикла каждое xp.evaluate занимает от 10 мс до 20 мс. К 15-му разу цикла каждое xp.evaluate занимает от 200 мс до 300 мс. К концу цикла (есть 150 элементов в узлах ) для каждой xp.evaluate требуется около 500-600 мсек.

Я пробовал использовать xp.compile (). Все компиляции занимают <5 мс. Я сделал xp.reset () (без разницы). Я создал новый объект XPath для каждой оценки (прибавляет около 4 мс).

Использование памяти не выходит из-под контроля во время выполнения.

Я запускаю это в одном потоке в тестовом примере JUnit, который не создает активности или чего-то подобного.

Я действительно озадачен.

Кто-нибудь знает, что еще попробовать?

Спасибо!

update

Если я запустил цикл for в обратном направлении ( for (int i = nodes.getLength () - 1; i> = 0; i -) ), то первые несколько узлов возьмите 500-600 мсек, а последние - 10-20 мсек. Итак, похоже, что это не имеет ничего общего с количеством вызовов, но вместо этого выражения, контекст которых находится ближе к концу документа, занимают больше времени, чем выражения, контекст которых находится рядом с началом документа.

Есть ли у кого-нибудь какие-нибудь мысли о том, что я могу с этим сделать?

22
задан Andrew Shelansky 23 September 2010 в 21:50
поделиться