62 votes

Décider de l'opportunité d'utiliser XmlDocument vs XmlReader

J'optimise un utilitaire personnalisé de sérialisation objet -> XML, et tout est fait et fonctionne et ce n'est pas le problème.

Il fonctionnait en chargeant un fichier dans un XmlDocument puis en passant récursivement par tous les nœuds enfants.

Je me suis dit que peut-être en utilisant XmlReader au lieu d'avoir XmlDocument charger/parser le tout serait plus rapide, donc j'ai implémenté cette version aussi.

Les algorithmes sont exactement les mêmes, j'utilise une classe d'enveloppe pour rendre abstraite la fonctionnalité de traitement d'une XmlNode contre un XmlReader . Par exemple, le GetChildren retourne soit un enfant XmlNode ou un SubTree XmlReader .

J'ai donc écrit un pilote de test pour tester les deux versions, en utilisant un ensemble de données non triviales (un fichier XML de 900kb avec environ 1.350 éléments).

Cependant, en utilisant JetBrains dotTRACE, je constate que le programme XmlReader est en fait plus lente que la version XmlDocument version ! Il semble qu'il y ait un traitement significatif impliqué dans XmlReader lire les appels lorsque je suis en itération sur les nœuds enfants.

Je dis tout ça pour demander ceci :

Quels sont les avantages/inconvénients de XmlDocument y XmlReader et dans quelles circonstances devez-vous utiliser l'un ou l'autre ?

Je pense qu'il y a un seuil de taille de fichier auquel XmlReader devient plus économique en termes de performances, ainsi que moins gourmand en mémoire. Toutefois, ce seuil semble se situer au-dessus de 1 Mo.

J'appelle ReadSubTree à chaque fois pour traiter les noeuds enfants :

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);
    }
}

Ce test s'applique à un grand nombre d'objets à un seul niveau (c'est-à-dire large et peu profond) - mais je me demande à quel point le test est efficace. XmlReader les tarifs lorsque le XML est profond et large ? Le XML que je traite ressemble beaucoup à un modèle d'objet de données, un objet parent pour de nombreux objets enfants, etc : 1..M..M..M

Je ne connais pas non plus à l'avance la structure du XML que j'analyse, je ne peux donc pas l'optimiser.

69voto

Zach Bonham Points 4460

Je l'ai généralement regardé pas du point de vue du plus rapide mais plutôt d'un utilisation de la mémoire perspective. Toutes les mises en œuvre ont été suffisamment rapides pour les scénarios d'utilisation dans lesquels je les ai utilisées (intégration d'entreprise typique).

Cependant, là où j'ai échoué, et parfois de façon spectaculaire, c'est en ne tenant pas compte de la taille générale du XML avec lequel je travaille. Si vous y réfléchissez dès le départ, vous vous épargnerez bien des soucis.

XML a tendance à gonfler lorsqu'il est chargé en mémoire, du moins avec un lecteur DOM comme XmlDocument o XPathDocument . Quelque chose comme 10:1 ? La quantité exacte est difficile à quantifier, mais si c'est 1 Mo sur le disque, ce sera 10 Mo en mémoire, ou plus, par exemple.

Un processus utilisant n'importe quel lecteur qui charge le document entier en mémoire dans son intégralité ( XmlDocument / XPathDocument ) peut souffrir d'une fragmentation importante du tas d'objets, ce qui peut finalement conduire à des problèmes de OutOfMemoryException (même avec de la mémoire disponible), ce qui entraîne l'indisponibilité du service/processus.

Étant donné que les objets dont la taille est supérieure à 85K finissent dans le tas des gros objets et que vous avez une explosion de taille de 10:1 avec un lecteur DOM, vous pouvez voir qu'il ne faut pas longtemps avant que vos documents XML soient alloués à partir du tas des gros objets.

XmlDocument est très facile à utiliser. Son seul véritable inconvénient est qu'il charge l'intégralité du document XML en mémoire pour le traiter. Son utilisation est d'une simplicité séduisante.

XmlReader est un lecteur basé sur le flux, ce qui maintiendra l'utilisation de la mémoire de votre processus généralement plus plate, mais il est plus difficile à utiliser.

XPathDocument a tendance à être une version plus rapide, en lecture seule, de XmlDocument, mais souffre toujours d'un gonflement de la mémoire.

22voto

Tarik Points 16118

Les données d'essai J'ai généré un fichier XML très simple avant chaque exécution d'un test. Les identifiants sont aléatoires et le nombre de nœuds "enfants" varie en fonction de l'exécution. Voici un exemple des données de test que j'ai utilisées.

...

Le test Comme je l'ai dit précédemment, je voulais comparer LINQ to XML, XmlDocument.Load, et XmlReader entre eux. J'ai exécuté chacune de ces technologies en utilisant 1, 10, 100, 1000, 10.000, 100.000 noeuds "enfants". Je les ai également comparées à un document XML utilisant les codages UTF-8, ASCII et UTF-32. Chaque itération a été exécutée 100 fois pour réduire les anomalies. Dans chacun des tests, j'appelle la méthode "ProcessId" qui simule le traitement de l'attribut "id".

XmlDocument.Load Je pensais que le code de XmlDocument.Load était le plus propre et le plus facile à comprendre, bien que je doive admettre que j'aime XPath. XmlDocument a quelques problèmes de sécurité, mais c'est un autre sujet. Voici le code que j'ai utilisé pour charger et rechercher le document :

private static void XmlDocumentReader(string fileName) {
    XmlDocument doc = new XmlDocument();
    doc.Load(fileName);
    XmlNodeList nodes = doc.SelectNodes("//child");
    if (nodes == null) {
        throw new ApplicationException("invalid data");
    }
    foreach (XmlNode node in nodes) {
        string id = node.Attributes["id"].Value;
        ProcessId(id);
    }
}

LINQ to XML LINQ to XML était également un code très facile à lire et à comprendre. J'ai constaté que même si LINQ to XML est censé utiliser des XmlReaders, l'appel à XDocument.Load lit l'intégralité du document en mémoire avant de le renvoyer. Donc si vous recherchez des données en haut ou au milieu d'un très gros document, cela peut être un problème. Voici le code que j'ai utilisé pour charger et rechercher le document :

private static void XDocumentReader(string fileName) {
    XDocument doc = XDocument.Load(fileName);
    if (doc == null | doc.Root == null) {
        throw new ApplicationException("invalid data");
    }
    foreach (XElement child in doc.Root.Elements("child")) {
        XAttribute attr = child.Attribute("id");
        if (attr == null) {
            throw new ApplicationException("invalid data");
        }
        string id = attr.Value;
        ProcessId(id);
    }
}

XmlReader XmlReader, plus précisément XmlTextReader, était le plus difficile à écrire et à comprendre. Avec sa particularité d'être un lecteur en avant seulement, vous devez prendre ce dont vous avez besoin pendant que vous l'avez, car vous ne pouvez pas revenir en arrière.

private static void XmlReaderReader(string fileName) {
    using (XmlReader reader = new XmlTextReader(fileName)) {
        while (reader.Read()) {
            if (reader.NodeType == XmlNodeType.Element) {
                if (reader.Name == "child") {
                    reader.MoveToAttribute("id");
                    string id = reader.Value;
                    ProcessId(id);
                }
            }
        }
    }
}

Les résultats Les résultats suivants sont en millisecondes pour chaque exécution. J'ai pris le temps total d'exécution et l'ai divisé par 100.

alt text

XmlReader bat LINQ to XML dans presque tous les cas, sauf pour les très petits documents XML. Ce qui est intéressant, c'est la façon dont les chiffres s'échelonnent entre les encodages. XmlReader est deux fois plus lent lors de la lecture de documents UTF-32 par rapport à des documents XML encodés en UTF-8 ou ASCII, alors que LINQ to XML et XmlDocument sont beaucoup moins lents. Si vous avez besoin de vitesse pour lire des documents XML, restez avec XmlReader. Si vous avez besoin de lisibilité et de maintenabilité de votre code, choisissez LINQ to SQL ou XmlDocument.

Source : LINQ to XML vs XmlDocument vs XmlReader

11voto

DSO Points 5942

XmlDocument est une représentation en mémoire de l'ensemble du document XML. Par conséquent, si votre document est volumineux, il consommera beaucoup plus de mémoire que si vous l'aviez lu en utilisant XmlReader.

Cela suppose que lorsque vous utilisez XmlReader, vous lisez et traitez les éléments un par un puis vous les jetez. Si vous utilisez XmlReader et construisez une autre structure intermédiaire en mémoire, vous avez le même problème, et vous allez à l'encontre de son objectif.

Google pour " SAX contre DOM "pour en savoir plus sur la différence entre ces deux modèles de traitement du XML.

0voto

Joe Points 60749

Il existe un seuil de taille à partir duquel XmlDocument devient plus lent, et finalement inutilisable. Mais la valeur réelle de ce seuil dépendra de votre application et du contenu XML, il n'y a donc pas de règle absolue.

Si votre fichier XML peut contenir de grandes listes (disons des dizaines de milliers d'éléments), vous devez absolument utiliser XmlReader.

0voto

David V. Corbin Points 76

La différence d'encodage est due au fait que deux mesures différentes sont mélangées. L'UTF-32 nécessite 4 octets par caractère, et est intrinsèquement plus lent que les données sur un seul octet.

Si l'on examine le test des grands éléments (100K), on constate que le temps augmente d'environ 70mS pour chaque cas, quelle que soit la méthode de chargement utilisée.

Il s'agit d'une différence (presque) constante causée spécifiquement par la surcharge par caractère,

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X