Decydowanie kiedy używać XmlDocument vs XmlReader

Optymalizuję niestandardowy obiekt - > narzędzie serializacji XML, i to wszystko jest zrobione i działa i to nie jest problem.

Zadziałało, ładując plik do obiektu XmlDocument, a następnie rekurencyjnie przechodząc przez wszystkie węzły potomne.

Uznałem, że być może użycie XmlReader zamiast XmlDocument Ładowanie/parsowanie całości będzie szybsze, więc zaimplementowałem również tę wersję.

Algorytmy są dokładnie takie same, używam klasy wrapper do abstrakcji funkcja radzenia sobie z XmlNode vs. an XmlReader. Na przykład, metody GetChildren yield zwracają potomek XmlNode lub poddrzewo XmlReader.

Napisałem więc sterownik testowy, aby przetestować obie wersje i używając nietrywialnego zestawu danych (plik XML 900kb z około 1350 elementami).

Jednak, używając JetBrains dotTRACE, widzę, że wersja XmlReader jest w rzeczywistości wolniejsza niż wersja XmlDocument! Wygląda na to, że w XmlReader odczytywanie połączeń, gdy jestem iteracja nad węzłami potomnymi.

Więc mówię to wszystko, aby zapytać:

Jakie są zalety / wady XmlDocument i XmlReader i w jakich okolicznościach należy je stosować?

Domyślam się, że istnieje próg rozmiaru pliku, przy którym XmlReader staje się bardziej ekonomiczna pod względem wydajności, a także mniej wymagająca pamięci. Próg ten wydaje się jednak przekraczać 1 MB.

Dzwonię ReadSubTree za każdym razem, aby przetworzyć węzły potomne:

public override IEnumerable<IXmlSourceProvider> GetChildren ()
{
    XmlReader xr = myXmlSource.ReadSubtree ();
    // skip past the current element
    xr.Read ();

    while (xr.Read ())
    {
        if (xr.NodeType != XmlNodeType.Element) continue;
        yield return new XmlReaderXmlSourceProvider (xr);
    }
}

Że test dotyczy wielu obiektów na jednym poziomie ( tj. wide & shallow) - ale zastanawiam się, jak dobrze XmlReader radzi sobie, gdy XML jest głęboki & szeroki? XML, z którym mam do czynienia, jest podobny do modelu obiektu Danych, 1 obiekt nadrzędny do wielu obiektów potomnych, itp.: 1..M..M..M

Nie znam też wcześniej struktury analizowanego XML, więc nie mogę go zoptymalizować.

Author: Danny Beckett, 2009-10-01

5 answers

Ogólnie patrzyłem na tonie z najszybszej perspektywy , ale raczej z perspektywywykorzystania pamięci . Wszystkie implementacje są wystarczająco szybkie, aby sprostać scenariuszom użycia, w których je wykorzystałem (typowa integracja korporacyjna).

Jednak tam, gdzie upadłem, a czasami spektakularnie, nie bierze się pod uwagę ogólnego rozmiaru XML, z którym pracuję. Jeśli pomyślisz o tym z góry, oszczędzisz sobie smutku.

XML wczytywać po wczytaniu do pamięci, przynajmniej z czytnikiem DOM jak XmlDocument LUB XPathDocument. Coś jak 10: 1? Dokładna ilość jest trudna do oszacowania, ale jeśli jest to 1MB na dysku, to będzie to 10MB w pamięci, lub więcej, na przykład.

Proces wykorzystujący dowolny czytnik, który ładuje cały dokument do pamięci w całości (XmlDocument/XPathDocument) może cierpieć z powodu fragmentacji sterty dużych obiektów, co ostatecznie może prowadzić do OutOfMemoryExceptions (nawet z dostępną pamięcią), powodując niedostępność usługi/procesu.

Ponieważ obiekty o rozmiarze większym niż 85K kończą się na stercie dużych obiektów, a Ty masz eksplozję o rozmiarze 10:1 z czytnikiem DOM, widać, że nie trzeba wiele, zanim dokumenty XML zostaną przydzielone ze sterty dużych obiektów.

XmlDocument jest bardzo łatwy w użyciu. Jego jedyną prawdziwą wadą jest to, że ładuje cały dokument XML do pamięci do przetworzenia. Jest uwodzicielsko prosty w użyciu.

XmlReader jest czytnikiem opartym na strumieniu dzięki temu wykorzystanie pamięci procesowej będzie ogólnie bardziej pochlebne, ale będzie trudniejsze w użyciu.

XPathDocument wydaje się być szybszą, tylko do odczytu wersją XmlDocument, ale nadal cierpi z powodu "wzdęcia" pamięci.

 65
Author: Zach Bonham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-16 01:16:00

XmlDocument jest reprezentacją w pamięci całego dokumentu XML. Dlatego jeśli twój dokument jest duży, pochłonie znacznie więcej pamięci niż gdybyś go przeczytał za pomocą XmlReader.

Zakłada się, że gdy używasz XmlReader, czytasz i przetwarzasz elementy jeden po drugim, a następnie je odrzucasz. Jeśli używasz Xmlreadera i konstruujesz inną strukturę pośredniczącą w pamięci, to masz ten sam problem i niszczysz jego cel.

Google dla " SAX versus DOM " aby dowiedzieć się więcej o różnicy między dwoma modelami przetwarzania XML.

 9
Author: DSO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-01 20:08:32

Inną kwestią jest to, że XMLReader może być bardziej wytrzymały do obsługi mniej niż idealnie uformowanego XML. Niedawno utworzyłem klienta, który zużywał strumień XML, ale strumień nie miał znaków specjalnych, które poprawnie uciekały w Uri zawartych w niektórych elementach. XMLDocument i XPathDocument odmówiły w ogóle załadowania XML, podczas gdy za pomocą Xmlreadera udało mi się wyodrębnić potrzebne informacje ze strumienia.

 4
Author: Display Name,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-13 16:03:07

Istnieje próg wielkości, przy którym XmlDocument staje się wolniejszy i ostatecznie bezużyteczny. Ale rzeczywista wartość progu będzie zależeć od twojej aplikacji i zawartości XML, więc nie ma twardych i szybkich reguł.

Jeśli Twój plik XML może zawierać duże listy (powiedzmy dziesiątki tysięcy elementów), zdecydowanie powinieneś używać XmlReader.

 0
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-01 16:43:27

Różnica w kodowaniu polega na tym, że mieszane są dwa różne pomiary. UTF-32 wymaga 4 bajtów na znak i jest z natury wolniejszy od danych jednobajtowych.

Jeśli spojrzysz na test dużego (100K) elementu, zobaczysz, że czas zwiększa się o około 70mS dla każdego przypadku, niezależnie od zastosowanej metody ładowania.

Jest to (prawie) stała różnica spowodowana konkretnie przez narzut na znak,

 0
Author: David V. Corbin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-11 15:52:28