IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Optimisation d'écriture XML


Sujet :

C#

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 8
    Points : 6
    Points
    6
    Par défaut Optimisation d'écriture XML
    Bonjour à tous,

    Dans le cadre d'un projet, je dois réaliser une petite DLL pour l'écriture d'un fichier XML de logs.

    J'ai déjà la DLL complète, cependant dans un soucis d'efficacité, j'ai commencé à tester les perfs ...

    J'ai fait une boucle simple de 1000 itérations pour le chargement en XML d'un message court (une fois en mode message, une fois erreur).

    Du type
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <logs>
        <log at="date" type="Message"> Ceci est un message</log>
        <log at="date" type="Erreur"> Ceci est une erreur </log>
    </logs>

    Pour écrire ces 1000 messages (500 de chaque) , je mets 12s (selon la config de l'ordi : Core2Duo 2.93Ghz avec 3Go de RAM). J'ai testé sur mon Core i5 je mets 2s.

    Je voulais savoir s'il y avait un moyen d'optimiser un peu cela, sachant que j'utilise un constructeur static pour limiter les accès disque au début (juste de la vérification de dossier et de fichier) , et que j'utilise un XDocument et un XElement pour l'écriture (avec un XmlWriter).


    Merci de me proposer vos éventuelles idées pour que je puisse réduire ce temps , car je trouve que 12s pour une écriture de messages est assez élevée (d'autant que ce temps augmente à 30s si je retente mes tests avec un fichier déjà créé avec 1000 messages ...).

    Merci d'avance

    Facultatif :
    J'ai cru comprendre qu'il pourrait être utile de passer par un FileStream (puis StreamWriter, XmlWriter) pour utiliser un buffer et flusher mes données par paquet.

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    332
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Juin 2002
    Messages : 332
    Points : 502
    Points
    502
    Par défaut
    Ça ne devrait pas prendre plus de temps d'insérer une ligne dans un fichier vide ou de 1 GB...

    Utilises-tu AppendChild ?

  3. #3
    Membre expert


    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2006
    Messages
    970
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 970
    Points : 3 304
    Points
    3 304
    Par défaut
    Bonjour,

    Je viens d'effectuer un test avec classe de log que j'ai écrite mais qui utilise un simple fichier .txt, donc sans XML et un StreamWriter. Pour 1000 enregistrements, moins de 1 seconde sur un core I5 dernière génération.

    Je pense que votre perte de performance viendrait plutôt de tout ce qui est constitution XML, mais je peux me tromper.
    Articles sur les technologies .NET

    Une réponse vous a aidé ? utilisez le bouton

    Votre problème est résolu ? utilisez le bouton

  4. #4
    Membre régulier
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2013
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2013
    Messages : 51
    Points : 83
    Points
    83
    Par défaut
    Bonjour,

    Pour optimiser au maximum, je vous conseille les actions suivantes :
    - générer le XML "à la main" (avec StringBuilder par exemple),
    - utiliser un FileWriter ou StreamWriter en mode bufferisé (voir cet article pour des infos sur les perfs: http://weblogs.asp.net/justin_rogers...10/179226.aspx)

    En espérant vous avoir aidé,
    Pascal
    Découvrez DotnetDojo, pour booster vos compétences de développeur

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 8
    Points : 6
    Points
    6
    Par défaut
    Voici ce que je fais pour le moment, ça sera plus simple.

    J'ai modifié la création de mon fichier en passant par un StringBuilder.

    Et erreur de ma part, il s'agissait de 2000 messages . Pour 1000 messages, sur la machine la moins performante, je mets 3s. Par contre je ne comprends toujours pas pourquoi ce temps est augmenté par 2 lorsque je relance mon test ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
     
            static Write()
            {
                // On vérifie l'existence du dossier, on le crée si besoin
                if (!Directory.Exists(nomDossier))
                    Directory.CreateDirectory(nomDossier);
     
                if (!File.Exists(nomFichier))
                {
                    StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"utf-8\"?><logs/>");
     
                    using (FileStream fs = new FileStream(nomFichier, FileMode.Create, FileAccess.Write, FileShare.Read))
                    {
                        using (StreamWriter sw = new StreamWriter(fs))
                            sw.Write(sb);
                    }
                }
            }
     
            /// <summary>
            /// Ces variables globales permettent de notifier le chemin du dossier
            /// Ainsi que le nom du fichier
            /// </summary>
            private static string nomDossier = @"C:\Log", nomFichier = nomDossier + @"\" + "log.xml";
     
            /// <summary>
            /// Fonction permettant d'ajouter un log avec un message simple dans le XML
            /// </summary>
            /// <param name="message">Message à ajouter</param>
            public static void write(bool estMessage, string message)
            {
                if (estMessage)
                    ajoutLog(new Log(TYPE.Message, message));
                else
                    ajoutLog(new Log(TYPE.Error, message));
            }
     
            /// <summary>
            /// Fonction surchargée pour prendre en compte les exceptions
            /// </summary>
            /// <param name="e">Exception à charger</param>
            public static void write(Exception e)
            {
                ajoutLog(new Log(e));
            }
     
            /// <summary>
            /// Fonction réalisant l'écriture dans le fichier XML
            /// </summary>
            /// <param name="logAdd">Log à écrire dans le fichier</param>
            private static void ajoutLog(Log logAdd)
            {
                XDocument docXml = new XDocument();
                XElement logs;
                //On charge les informations de notre fichier
                docXml = XDocument.Load(nomFichier);
                logs = docXml.Element("logs");
     
                //On spéficie ici les paramètres d'écriture du XML...
                XmlWriterSettings ws = new XmlWriterSettings();
                //Afin de faire une indentation propre de notre fichier
                ws.Indent = true;
     
                /* On va ensuite créer un élément log pour inscrit les informations nécessaires
                 * at = heure de création
                 * type = type du log
                 * On charge ensuite le message que l'on a pour le log
                 */
                XElement add =
                    new XElement("log",
                        logAdd.exceptionMessage,
                        new XAttribute("at", logAdd.at.ToString()),
                        new XAttribute("type", logAdd.type.ToString()));
     
                // On va ensuite réaliser différent traitement selon le type de notre Log ...
                if (logAdd.type == TYPE.Exception)
                {
                    // On crée un élément pour l'attribut Stack
                    XElement stackAttrib = new XElement("stack", logAdd.stackException);
     
                    // On rajoute un fils à l'élement log
                    add.Add(stackAttrib);
     
                    // On vérifie que l'exception possède une innerException ...
                    if (logAdd.innerMessage != null)
                    {
                        /*... On va alors créer un élément afin de créer cette inner avec
                         * les information nécessaires (at/type/message/stack) ...
                        */
                        XElement innerElement =
                            new XElement("log", logAdd.innerMessage,
                                new XAttribute("at", logAdd.at.ToString()),
                                new XAttribute("type", "InnerException"),
                                new XElement("stack", logAdd.stackInner)
                                );
     
                        // ... Puis finalement ajouter cette nouvelle branche au log
                        add.Add(innerElement);
                    }
                }
     
                // On ajoute finalement notre branche "log" à notre racine
                logs.Add(add);
     
                //Puis on sauvegarde notre ajout
                docXml.Save(nomFichier);
            }

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Le format XML est inadapté pour un fichier de log (*) : en effet, à chaque fois que tu dois ajouter un message, il faut enlever la balise de fermeture de l'élément racine, ajouter le message, et refermer l'élément racine. Vu que la plupart des APIs XML ne savent pas gérer ça "intelligemment", en pratique tu réécris la totalité du fichier à chaque fois, ce qui est est très inefficace...

    Tu ferais mieux de faire un log en texte brut, ou d'utiliser l'event log de Windows

    (*) d'ailleurs, d'une manière générale, le format XML n'est pas vraiment fait pour être modifié régulièrement. Typiquement, tu l'écris une fois et tu n'y touches plus, ou alors pas souvent.

  7. #7
    Futur Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 8
    Points : 6
    Points
    6
    Par défaut
    Malheureusement je réalise cela dans le cadre d'un projet, et c'est écrit dans le cahier des charges que je dois réaliser les logs sous format XML ...

  8. #8
    Membre régulier
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2013
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2013
    Messages : 51
    Points : 83
    Points
    83
    Par défaut
    Kurus,

    En fait quand je parlais de StringBuilder, je pensais à tout écrire comme ça, sans passer par les balises XElement ou XmlDocument.

    Mais comme le dis tomlev, Xml n'est pas adapté pour des données en mode "append". Et c'est vrai que je n'ai jamais vu ça dans aucun projet à ma connaissance.

    Une idée à creuser: pourquoi ne pas stocker en format texte (ligne par ligne) et écrire un morceau de code qui va créer le fichier XML à partir des logs "plats".
    Dans ce cas, il n'est pas nécessaire de charger à chaque fois les logs pour ajouter un élément... ce qui serait beaucoup plus rapide.
    Découvrez DotnetDojo, pour booster vos compétences de développeur

  9. #9
    Futur Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 8
    Points : 6
    Points
    6
    Par défaut
    Pour la simple et bonne raison que je vais me servir de ma DLL comme de Log4Net.

    En fait je pense que mon prof souhaite que l'on refasse un peu le comportement de Log4Net, mais en le faisant nous même.

    Je ne sais pas potentiellement à quel moment mon programme va écrire dans mon XML, car il va lever des messages d'erreurs, des exceptions etc ...

    Le principe est que nous créions une DLL qui puisse permettre à un développeur lambda de mettre dans son prog des méthodes de logs XML. Puis nous mettons à dispo une interface pour afficher proprement les logs et faire diverses traitements dessus (tri, sélection etc...).

    Ma DLL fonctionne, ce n'est pas le problème, c'est juste que je souhaitais optimiser un peu tout ça. Mais si ça n'est pas possible, je laisse comme ça =)

  10. #10
    Membre régulier
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2013
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2013
    Messages : 51
    Points : 83
    Points
    83
    Par défaut
    Très bien, je vois.


    Si vous souhaitez approfondir le sujet, je suis à votre disposition.

    Pascal
    Découvrez DotnetDojo, pour booster vos compétences de développeur

  11. #11
    Membre expert


    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2006
    Messages
    970
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 970
    Points : 3 304
    Points
    3 304
    Par défaut
    Peut-être une piste, bonne ou non je ne sais pas.

    Pourquoi ne pas maintenir un DataSet avec une simple table avec les quelques informations dont vous avez besoin dans un message d'erreur (l'heure, le message, code d'erreur, ...). Quand un problème survient vous l'ajouter à ce Dataset. Et vous utilisez la méthode WriteXml pour le sauver (à voir si vous voulez sauver dans le log à chaque erreur ...).

    Si vous devez plus tard afficher le contenu de votre fichier, c'est un bon point de départ pour afficher les informations dans un ListView ou DataGrid bindé sur le DataSet.
    Articles sur les technologies .NET

    Une réponse vous a aidé ? utilisez le bouton

    Votre problème est résolu ? utilisez le bouton

  12. #12
    Futur Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2011
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 8
    Points : 6
    Points
    6
    Par défaut
    Merci pour vos réponses, je vais laisser comme ça.

    Mon temps de lecture étant relativement petit (55 ms sur la moins bonne machine) , je passe en

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Optimisation chargement fichier xml
    Par djspank dans le forum Linq
    Réponses: 9
    Dernier message: 11/12/2009, 11h36
  2. optimisation lecture/écriture de txt volumineux
    Par tibofo dans le forum VB 6 et antérieur
    Réponses: 10
    Dernier message: 25/01/2009, 14h00
  3. Optimisation TreeView avec XML
    Par tmryuga dans le forum Composants VCL
    Réponses: 3
    Dernier message: 19/11/2007, 14h27
  4. [XSLT] Comment optimiser les traitements XML/XSL ?
    Par thibaut06 dans le forum Bibliothèques et frameworks
    Réponses: 1
    Dernier message: 24/03/2006, 16h39
  5. Optimisation java et xml
    Par ujoodha dans le forum XML/XSL et SOAP
    Réponses: 2
    Dernier message: 25/10/2005, 14h53

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo