web-dev-qa-db-fra.com

Décider quand utiliser XmlDocument vs XmlReader

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

Cela a fonctionné en chargeant un fichier dans un objet XmlDocument, puis en parcourant récursivement tous les nœuds enfants.

J'ai pensé que peut-être utiliser XmlReader au lieu d'avoir XmlDocument charger/analyser l'ensemble serait plus rapide, j'ai donc implémenté cette version également.

Les algorithmes sont exactement les mêmes, j'utilise une classe wrapper pour résumer la fonctionnalité de traiter un XmlNode contre un XmlReader. Par exemple, les méthodes GetChildren yield retournent un enfant XmlNode ou un SubTree XmlReader.

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

Cependant, en utilisant JetBrains dotTRACE, je vois que la version XmlReader est en fait plus lente que la version XmlDocument! Il semble qu'un traitement important soit impliqué dans les appels de lecture XmlReader lorsque j'itère sur des nœuds enfants.

Je dis donc tout cela pour demander ceci:

Quels sont les avantages/inconvénients de XmlDocument et XmlReader, et dans quelles circonstances devez-vous les utiliser?

Je suppose qu'il existe un seuil de taille de fichier auquel XmlReader devient plus économique en termes de performances, ainsi que moins gourmand en mémoire. Cependant, ce seuil semble être supérieur à 1 Mo.

J'appelle ReadSubTree à chaque fois pour traiter les nœuds 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 à beaucoup d'objets à un seul niveau (c'est-à-dire large et peu profond) - mais je me demande dans quelle mesure XmlReader s'en sort quand le XML est profond et large? C'est à dire. le XML que je traite ressemble beaucoup à un modèle d'objet de données, 1 objet parent à 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.

61
PhilChuang

Je l'ai généralement regardé non pas du point de vue le plus rapide , mais plutôt d'une utilisation de la mémoire perspective. Toutes les implémentations ont été assez rapides pour les scénarios d'utilisation dans lesquels je les ai utilisées (intégration d'entreprise typique).

Cependant, là où je suis tombé, et parfois de manière spectaculaire, je ne prends pas en compte la taille générale du XML avec lequel je travaille. Si vous y réfléchissez dès le départ, vous pouvez vous épargner du chagrin.

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

Un processus utilisant n'importe quel lecteur qui charge l'intégralité du document dans la mémoire dans son intégralité (XmlDocument/XPathDocument) peut souffrir d'une fragmentation de tas d'objets volumineux, qui peut finalement conduire à OutOfMemoryExceptions ( même avec la mémoire disponible) entraînant un service/processus indisponible.

Étant donné que les objets d'une taille supérieure à 85 Ko se retrouvent sur le tas d'objets volumineux et que vous avez une explosion de taille 10: 1 avec un lecteur DOM, vous pouvez voir que cela ne prend pas beaucoup de temps avant que vos documents XML ne soient alloués à partir de le tas de 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 à traiter. Son séduisant simple à utiliser.

XmlReader est un lecteur basé sur les flux, donc votre utilisation de la mémoire de processus sera généralement plus plate mais sera plus difficile à utiliser.

XPathDocument a tendance à être une version plus rapide et en lecture seule de XmlDocument, mais souffre toujours de la mémoire "ballonnement".

69
Zach Bonham

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

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

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

11
DSO

Une autre considération est que XMLReader pourrait être plus robuste pour gérer du XML moins que parfaitement formé. J'ai récemment créé un client qui consommait un flux XML, mais le flux n'avait pas les caractères spéciaux correctement échappés dans les URI contenus dans certains des éléments. XMLDocument et XPathDocument ont refusé de charger le XML, alors qu'en utilisant XMLReader j'ai pu extraire les informations dont j'avais besoin du flux.

4
Display Name

La différence de codage est due au fait que deux mesures différentes sont mélangées. UTF-32 nécessite 4 octets par caractère et est intrinsèquement plus lent que les données à un octet.

Si vous regardez le test des grands éléments (100K), vous voyez que le temps augmente d'environ 70 ms 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,

0
David V. Corbin

Il existe un seuil de taille auquel XmlDocument devient plus lent et finalement inutilisable. Mais la valeur réelle du seuil dépendra de votre application et du contenu XML, il n'y a donc pas de règles strictes et rapides.

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

0
Joe