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ć.
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 OutOfMemoryException
s (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.
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.
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.
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.
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,
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