7
votes

Durée d'exécution quadratique pour les routines Delphi XML (MSXML)

Au travail, nous utilisons un fichier journal XML. Chaque message journal est un bloc code> avec code> et code> Sous-noode, il y a Code> Blocs,

Code> Construit et ainsi de suite et le fichier journal peut être transformé en HTML localisé à l'aide du traitement Delphi et XSLT ultérieurement.

Pour les fichiers journaux de taille moyenne (environ 2 Mo) , nous avons eu des problèmes de performance (jusqu'à une minute de chargement du XML et de faire des manipulations de base) et je pourrais les réduire à un projet de test comme celui-ci (Modifier: Mise à jour du code et des mesures ajoutées): P>

Node count      8000    10000   12500   15625   19531   24413   30516   38145   47681
Base test time  484     781     1140    1875    2890    4421    6734    10672   16812
Variation 1                             32      47      62      78      78      141
Variation 2     2656    3157    3906    5015    6532    8922    12140   17391   24985
  (delta Base)   2172    2376    2766    3140    3642    4501    5406    6719    8173


8 commentaires

Ce n'est pas vraiment un problème Delphi. Les routines XML en question sont simplement une interface avec la bibliothèque Standard MSXML MSXML Windows.


XML n'est pas bon pour la journalisation. La meilleure option que vous avez est d'ouvrir le fichier, de localiser la dernière balise (espérons-le automatiquement automatiquement par la taille connue, appendez vos nouveaux nœuds, puis appendez à nouveau la dernière balise. Sinon que vous êtes sur un perdant.


@ Masonwheeler: Merci d'avoir souligné cela, bien que je sache et cela change simplement le bouc émissaire. La question reste donc la même.


@ MJ2008: Ajout de nouveaux messages est effectué comme si vous avez décrit et que le fichier journal est uniquement chargé dans son ensemble lors de la convertie en HTML, le problème n'affecte donc pas le processus de journalisation principal. Néanmoins, XML présente des avantages ici comme mentionné, par ex. XSLT est très utile et tout ce qui est utilisé dans le flux de travail est "UTF prêt".


Avez-vous essayé de mesurer le temps de ce code? Je pense que la plupart du temps est dépensé pour loadfromfile () . Je vous recommande de regarder nativexml et omnixml analyseurs.


@Teran: J'ai fait des mesures il y a quelques mois et je pourrais éditer la question demain après les avoir examinées, mais afaire un seul Chargéfromfile () appel sans autre modification XML était très rapide et ne fait que lentement lorsque Ajout de modifications (et seule la première modification est lente), il semble donc utiliser l'initialisation / validation retardée.


Les API basées sur DOM @schnaader sont toujours faciles à utiliser, mais lentement. D'autre part, les API de SAX sont assez difficiles à travailler, mais rapides.


Mise à jour de la question avec des mesures de code et de temps complets, a également changé «exponentiel» à «quadratique» pour clarification.


4 Réponses :


7
votes

Je suis d'accord avec MJ2008 que XML n'est pas un bon ajustement pour la journalisation. Cela dit, ce problème et de grands fichiers XML en général peuvent être traités plus rapidement en utilisant SAX , il lance des événements lors de l'analyse du flux entrant de données XML, ce qui vous permet de traiter les éléments tels qu'ils sont lus à partir du disque, en atténuation de l'exponentialité du chargement de la mémoire en mémoire avant le remettre à xslt.

Je regrette que je n'ai pas fait SAX dans Delphi (encore), mais je soupçonne que la partie la plus difficile implémente les interfaces saxoques requises (par exemple, IsaxContHandler ), mais Delphi a TinterfaCedObject et TautoObject et d'autres pour cela.


3 commentaires

Cette réponse me confond encore plus. Vous dites que SAX améliore la performance que je comprends parfaitement, mais pourquoi a-t-il toujours des heures d'exécution exponentielle lors du chargement? Quelle est la raison pour analyser la seconde moitié des nœuds x prend deux fois plus longtemps que la première moitié? Je le comprendrais peut-être pour un pire des cas xml arborescence (noeuds nichés x), mais pour la structure simple d'un fichier journal (x des nœuds de message séparé), le temps d'exécution non linéaire semble faux.


L'analyse de SAX va échouer linéairement avec la taille du fichier d'entrée


Je vais juste faire confiance à David pour maintenant et +1 et accepter votre réponse car SAX aurait été l'une des choses que j'aurais essayé ensuite. Si cela a aussi un comportement exponentiel, je posterai une nouvelle question ou modifierai celui-ci, mais j'en doute. Merci!



4
votes

Votre question en un mot: pourquoi la bibliothèque binaire msxml est-elle si lente? Qui sait. On s'en fout. Allez-vous le désassembler? Casser à Microsoft et saisir son code source? Ce n'est pas Delphi ici, c'est le code Microsoft.

Bien que XML est un mauvais choix pour la journalisation, Omnixml est probablement un meilleur choix que MSXML.

Cependant, un choix bien meilleur est appelé "Fichier texte ouvert pour l'annexe, Ligne d'écriture, Fermer le fichier texte". Notez l'évolutivité inhérente et le manque d'analyse requise.


1 commentaires

+1 parce que vous avez absolument raison, et ce que j'ai fait pour résoudre les problèmes dans ces directions. J'étais juste des curiosités si quelqu'un ici est peut-être aussi connu la réponse. BTW, je suis assez proche d'inspecter / désassembler ou du moins de faire des recherches supplémentaires sur le sujet, car je m'intéresse pourquoi / comment ils ont vissé msxml up si mauvais.



1
votes

Utilisez-vous le terme "exponentiel" dans un sens mathématique, ou juste dans un sens populaire? Il serait intéressant de savoir, par exemple, que ce soit vraiment quadratique, ou s'il s'agit d'une sorte de fonction où la performance est relativement linéaire jusqu'à ce que vous frappiez un seuil (taille de la mémoire) auquel cela se dégrade soudainement.

Si cela prend une minute pour traiter 2 Mo, alors quelque chose est très mal faux. Je ne connais pas votre environnement assez bien pour commencer à deviner, mais cela devrait prendre au plus une seconde. Vous devez explorer pour trouver où se passe le moment. Commencez par établir si elle dépense son temps à l'analyse du XML, ou le traitement du XML après l'analyse est terminé.


5 commentaires

Je mettrai à jour la question avec le code complet, les exécutions et l'utilisation de la mémoire bientôt. J'utilise "exponentiel" dans un sens mathématique, par ex. Pour une "base" XML 10 Ko de taille, le traitement 20 Ko prend environ 4 fois plus longtemps, 40 Ko prend environ 16 fois plus longtemps et ainsi de suite. Mais votre question est toujours valide, car je n'ai coché que 3-5 valeurs la dernière fois et n'a pas fait une analyse complète d'exécution.


Ce serait une échelle quadratique. Êtes-vous par hasard à l'aide de Bubble Tri?


@DavidHeffernan: Je ne fais rien qui expliquerait le comportement quadratique, c'est pourquoi je suis si intéressé par la raison ou ce que MSXML va mal ici. Je peux même réduire le problème à deux appels d'API, charger un XML et compter ses nœuds.


Quelle partie de celle-ci est quadratique? Chargement ou comptage?


Compter, mais cela ne dépend pas si je compte les nœuds ou effectuez une autre opération sur le XML, il semble qu'il y ait une initialisation / validation retardée en cours et les opérations après cela montrant un comportement "normal" attendu.



3
votes

Contrairement aux commentaires des autres, je pense que XML est un excellent format de journalisation. Les wrappers Delphi VCL pour XML sont très métisseurs de mémoire gourmands. Cela peut donc expliquer la performance médiocre du traitement pure txmldocument à l'échelle.

Je recommanderais plutôt de publier sur votre journal XML en utilisant une simple transformation XSLT. Je n'ai pas mesuré la performance de cette solution à l'échelle, mais je pense que ce sera une vaste amélioration de ce que vous rapportez actuellement.

la feuille de style.

Par exemple Supposons que notre journal ait quelque chose comme ça ... xxx

Cette simple feuille de style XSLT 1.0, avec paramètre addend-message ... < / p> xxx

... ajoutera un message au journal.

la liaison de langue

pour atteindre cet objectif dans Delphi, utilisez le Après des déclarations ... xxx

créer une itransform, passant dans la feuille de style comme une chaîne. Définissez les deux propriétés de nom de fichier au nom de fichier du journal. Chaque fois que vous devez ajouter un message au journal, appelez addparameter () , puis transformer () .

Détails de la mise en œuvre de la solution

Une implémentation possible pour la liaison de langue susmentionnée peut être ... xxx

Ceci se lie à MS MS XML Bibliothèque de Microsoft et moteur XSLT. Malheureusement, je ne connais aucun moyen pratique de lier Processeur XSLT de Saxon à Delphi Code .

Mise en œuvre alternative

Une mise en œuvre alternative pour tirer parti de MSS XSLT Le moteur est donné par Ma réponse ici . L'inconvénient de cette méthode est que la paramétrage n'est pas indigène. Pour paramétrer la feuille de style, vous devriez rouler le vôtre, en effectuant une chaîne Remplacer sur la feuille de style avant la transformation.

Considérations de performance

Si vous faites beaucoup de journalisation rapidement Cela peut être une bonne stratégie pour mettre en cache les messages à enregistrer la mémoire, puis à intervalles réguliers mais pas trop fréquents, purge votre cache avec une seule transformation XSLT pour écrire tous vos messages.


2 commentaires

+1, légèrement offtopique alors que la journalisation elle-même n'est pas mon problème, mais c'est un bon moyen de faire le principal travail de journalisation.


+1 pour une idée folle. Je pense toujours que cela souffre de trop de complexité. Les fichiers texte sont meilleurs.