2009-10-01 3 views
60

Sto ottimizzando un oggetto personalizzato -> XML serialization utility, e tutto è fatto e funzionante e non è questo il problema.Decidere su quando utilizzare XmlDocument contro XmlReader

Ha funzionato caricando un file in un oggetto XmlDocument, quindi passando in modo ricorsivo attraverso tutti i nodi figlio.

Ho pensato che forse usando XmlReader invece di avere caricare/analizzare l'intera cosa sarebbe più veloce, così ho implementato anche quella versione.

Gli algoritmi sono esattamente gli stessi, io uso una classe wrapper per astrarre la funzionalità di gestire uno XmlNode rispetto a XmlReader. Ad esempio, i metodi GetChildren restituiscono un figlio XmlNode o un sottotabella XmlReader.

Così ho scritto un test driver per testare entrambe le versioni e utilizzare un set di dati non banale (un file XML 900kb con circa 1.350 elementi).

Tuttavia, utilizzando JetBrains dotTRACE, vedo che la versione XmlReader è in realtà più lenta della versione XmlDocument! Sembra che ci sia qualche significativa elaborazione coinvolta nelle chiamate di lettura XmlReader quando sto iterando su nodi figlio.

Così dico tutto ciò che a chiedere questo:

quali sono i vantaggi/svantaggi di XmlDocument e XmlReader, e in quali circostanze si deve utilizzare uno?

La mia ipotesi è che ci sia una soglia di dimensione del file in cui XmlReader diventa più economico in termini di prestazioni, nonché una minore quantità di memoria. Tuttavia, tale soglia sembra essere superiore a 1 MB.

sto chiamando ReadSubTree ogni tempo per elaborare i nodi secondari:

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

Questo test è applicabile a un sacco di oggetti a livello di singola (cioè un'ampia & poco profondo) - ma mi chiedo come ben XmlReader tariffe quando l'XML è profondo & largo? Cioè l'XML che sto trattando è molto simile a un modello di oggetto dati, 1 oggetto genitore a molti oggetti figlio, ecc: 1..M..M..M

Inoltre non conosco in anticipo la struttura dell'XML che sto analizzando, quindi posso ottimizzare per questo.

+1

Mi sono sempre chiesto perché c'era sia un XmlDocument che un XmlReader ... –

+0

In realtà esiste un'altra opzione per XMLDocument e XMLReader. Ora puoi utilizzare LINQ in XML, ma in realtà XMLReader è più efficiente in molti modi. – Tarik

+2

Attendi. Il metodo 'GetChildren' restituisce un' XmlReader'? Vuoi dire, stai chiamando 'XmlReader.Create()' ogni volta che elabori un nodo figlio? –

risposta

63

ho generalmente guardato non da una prospettiva più veloce, ma piuttosto da un utilizzo prospettiva memoria. Tutte le implementazioni sono state abbastanza veloci per gli scenari di utilizzo in cui le ho utilizzate (tipica integrazione aziendale).

Tuttavia, dove sono caduto, ea volte in modo spettacolare, non sto prendendo in considerazione le dimensioni generali dell'XML con cui lavoro. Se ci pensi in anticipo puoi risparmiare un po 'di dolore.

XML tende a gonfiarsi quando viene caricato in memoria, almeno con un lettore DOM come o XPathDocument. Qualcosa come 10: 1? L'importo esatto è difficile da quantificare, ma se è 1 MB su disco sarà 10 MB in memoria, o più, per esempio.

Procedimento utilizzando qualsiasi lettore che carica l'intero documento in memoria nella sua interezza (XmlDocument/XPathDocument) possono soffrire di grande frammentazione oggetto mucchio, che alla fine possono portare a OutOfMemoryException s (anche con memoria disponibile) determinando un servizio disponibile /processi.

Dato che gli oggetti che sono maggiori di 85K di dimensione finiscono sul grande mucchio oggetto, e hai un 10: esplosione taglia 1 con un lettore di DOM, si può vedere che non ci vuole molto prima I documenti XML vengono allocati dall'heap di oggetti di grandi dimensioni.

XmlDocument è molto facile da usare. Il suo unico svantaggio è che carica l'intero documento XML in memoria per l'elaborazione. È seducentemente semplice da usare.

XmlReader è un lettore basato sul flusso, pertanto manterrà l'utilizzo della memoria di processo generalmente più piatto ma più difficile da utilizzare.

XPathDocument tende ad essere una versione di XmlDocument più veloce e di sola lettura, ma soffre ancora di memoria "ingombrante".

+4

Il caricamento di documenti XML, per quanto grande, in memoria NON causa oggetti di grandi dimensioni. Tuttavia tenere l'XML come una stringa! È la dimensione dei singoli oggetti che contano rispetto alla capacità dei GC di deframmentare la memoria, ma la dimensione totale del grafico dell'oggetto che importa rispetto all'utilizzo della memoria. –

+1

FWIW Ho appena fatto un punto di riferimento tra XDocument, XMLReader e XmlDocument. Per fare percorsi simili hanno preso rispettivamente 0,004, 0,001 e 0,692 secondi. – micahhoover

0

C'è una soglia di dimensione in cui XmlDocument diventa più lento e alla fine inutilizzabile. Ma il valore effettivo della soglia dipenderà dall'applicazione e dal contenuto XML, quindi non ci sono regole rigide e veloci.

Se il file XML può contenere elenchi di grandi dimensioni (ad esempio decine di migliaia di elementi), è consigliabile utilizzare XmlReader.

9

XmlDocument è una rappresentazione in memoria dell'intero documento XML. Quindi se il tuo documento è grande, allora consumerà molta più memoria che se lo avessi letto usando XmlReader.

Si presume che quando si utilizza XmlReader si leggano ed elaborino gli elementi uno alla volta e poi lo si elimina.Se usi XmlReader e costruisci un'altra struttura intermedia in memoria, hai lo stesso problema e ne stai sconfiggendo lo scopo.

Google per "SAX versus DOM" per ulteriori informazioni sulla differenza tra i due modelli di elaborazione XML.

+1

La cosa fastidiosa è che non c'è assolutamente alcuna indicazione su dove (ballpark) un documento diventa "grande" e XmlReader inizia a produrre vantaggi considerevoli. È 1KB, 1 MB o anche molto altro? Sono sicuro che la risposta è "dipende", ma senza un indizio siamo lasciati a determinare queste cose sperimentalmente caso per caso, tranne nei casi in cui essere in grado di gestire dati arbitrariamente grandi è un requisito (quindi XmlReader è la scelta chiara). –

0

La differenza di codifica è dovuta alla combinazione di due misurazioni diverse. UTF-32 richiede 4 byte per carattere ed è intrinsecamente più lento dei dati a byte singolo.

Se si esamina il test di elementi di grandi dimensioni (100 K), si vede che il tempo aumenta di circa 70 mS per ciascun caso indipendentemente dal metodo di caricamento utilizzato.

Questo è un (quasi) costante differenza causata specificamente dal per carattere ambientale,

4

Un'altra considerazione è che XMLReader potrebbe essere più robusto per gestire meno-che-perfettamente formato XML. Di recente ho creato un client che utilizzava un flusso XML, ma il flusso non aveva i caratteri speciali sfuggiti correttamente negli URI contenuti in alcuni degli elementi. XMLDocument e XPathDocument hanno rifiutato di caricare l'XML, mentre con XMLReader ero in grado di estrarre le informazioni necessarie dallo streaming.