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

SL & STL C++ Discussion :

[std::ifstream] Lecture formatée lente


Sujet :

SL & STL C++

  1. #1
    Membre éclairé Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Points : 871
    Points
    871
    Par défaut [std::ifstream] Lecture formatée lente
    Salut,

    Quelqu'un m'a demandé comment optimiser une lecture de fichier formatée qui était trop lente, et je ne savais pas vraiment comment faire.

    Je lui ai d'abord demandé s'il ne pouvait pas utiliser des bibliothèques déjà faites, mais il ne savait pas si son tuteur l'autorisait à le faire.

    Les fichiers qu'il doit lire sont des images au format texte, .ppm, qui se présente sous la forme suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    P3
    # commentaire... genre généré par Irfanview
    128 128
    255
    0 255 255 0 128 120 ...
    ...
    - La première ligne, c'est un nom de code.
    - La deuxième ligne, c'est un commentaire.
    - La 3e ligne : largeur et hauteur
    - La 4e ligne : la valeur max autorisée pour les entiers qui suivent
    - Le reste des lignes (le nombre d'entiers sur une ligne n'est pas constant) : les composantes RVB de chaque pixel.

    Il utilise std::ifstream pour lire, il alloue le vecteur de pixel à l'avance dès que la taille de l'image est connue, et il fait une double boucle pour lire les pixels du fichier.

    Le problème, c'est pour charger une image genre qui fait environ 4.5 Mo (ça fait environ 640x480 pixels), ça met 3 secondes sur son ordinateur environ, alors qu'Irfanview le lit quasi instantanément.

    C'est bien trop lent, il est censé analyser des images qui sortent d'une webcam à une fréquence assez soutenue genre 10 fois par sec.

    • Comment s'y prendre ? std::streambuf, c'est pas pour des choses formatées.
    • C'est pas mieux de charger le tout dans un std::string et d'utiliser un parseur ?

  2. #2
    Membre éclairé

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Points : 858
    Points
    858
    Par défaut
    Si les performances sont importantes mieux vaut choisir un format d'image binaire (code P6 au lieu de P3 dans le ppm par exemple).

    Mais même dans ce cas, il faudra une machine très rapide pour traiter 10 images par seconde (~10Mo par seconde en lecture/écriture).

    En général, pour du temps réel, on ne passe pas par le disque, on traite tout directement en RAM.

  3. #3
    Membre éclairé Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Points : 871
    Points
    871
    Par défaut
    Bah, je serais bien passé au format binaire à sa place, mais c'est pas mon projet :/.

    C'est sûr c'est plus rapide, mais comment le logiciel Irfanview arrive-t-il à le charger en 2 ou 3 dixièmes de secondes ?

    (peut-être qu'en fait pour l'instant il travaille avec P3 pour tester les fonctionnalités, puis je pense pas que sa webcam créerait des fichiers au format texte).

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Salut,

    Ce que tu peux faire, c'est de passer par un buffer qui prend l'ensemble de l'image d'une seule traite...

    Ainsi, la gestion restante se fera directement au travers d'informations contenues dans la ram, et non plus au travers d'un acces disque

    Pour ce faire, tu peux te baser sur l'entrée de la faq qui en parle: http://c.developpez.com/faq/cpp/?pag...RS_full_buffer

    Je ne serais pas tres étonné que ce simple fait permettra déjà d'obtenir de bien meilleures performances, meme en considérant le temps nécessiare à la convertion des valeurs à lire, du simple fait que tout le fichier sera lu d'une seule traite, alors que sinon, il faille attendre, parfois, que le disque dur termine son tour afin de retrouver le secteur auquel il doit accéder
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    38
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 38
    Points : 44
    Points
    44
    Par défaut
    Un exemple qui indique comment fixer la taille du buffer:

    http://www.cplusplus.com/reference/i...pubsetbuf.html

    // set character buffer (pubsetbuf)
    #include <fstream>
    using namespace std;

    int main () {

    char mybuffer [512];
    fstream filestr;
    filestr.rdbuf()->pubsetbuf(mybuffer,512);

    // operations with file stream here.

    return 0;
    }

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Heu...

    En quoi l'entrée de la FAQ que je présente te chagrine-t-elle

    D'autant plus qu'il s'agit, non pas de fixer la taille du buffer du fichier, mais bel et bien de récupérer l'intégralité du fichier dans une structure qui nous permettra d'en récupérer les données par la suite...

    En gros, le code final serait sans doute du genre de
    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
     
    //ouverture du fichier
     
    std::ifstream fichier(nom.c_str());//ou nom est une std::string contenant
                                      //... le nom du fichier à ouvrir
    if(fichier)
    {
        std::stringstream buffer;
        buffer<<fichier.rdbuf();
        fichier.close();
        std::string str;
        buffer>>str;
        //la première ligne doit etre "P3"
        if(str!="P3") //c'est peut etre à adapter ;)
            throw std::runtime_error("format invalide");
        la deuxième ligne doit etre un commentaire
        std::getline(buffer,str);
        if(str[0]!='#')
            throw std::runtime_error("format invalide");
        int ligne;
        int colone;
        buffer>>ligne>>colone;
        //création du tableau à afficher (il s'agit en fait d'un tableau de char
        //dont les valeurs doivent etre récupérée
        char *final=new char[ligne*colone];
        //la dernière boucle
        for(int i=0;i< ligne*colone;i++) //si le compilo fait bien son travail, 
        // ce ne sera pas plus lent que d'avoir calculé un total=ligne*colone
        // au par avant
        {
            //ce qu'on lit, c'est un entier
            int lu;
            buffer>>lu;
            fini[i]=(char)lu;//permet de ne prendre que les 8 bits de l'entier qui
                             //nous intéresse
        }
        //on peut retourner le tableau final
        return fini;
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    38
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 38
    Points : 44
    Points
    44
    Par défaut
    Citation Envoyé par koala01
    Heu...
    En quoi l'entrée de la FAQ que je présente te chagrine-t-elle
    Je ne sais pas si çe message m'est destiné, mais l'entrée de la FAQ ne me chagrine pas, je suis désolé si tu l'as ressenti comme ça.
    Je voulais simpement préciser qu'en augmentant la taille du buffer on pouvait (peut être) réduire le temps d'exécution en effectuant moins d'appels système.

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    SiSi... il t'était tout spécialement adressé, mais sans aucune idée offencente
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre éclairé Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Points : 871
    Points
    871
    Par défaut
    Salut,

    - j'ai essayé avec les std::stringstream, mais en fait, ça change rien au niveau performance. En fait, c'est encore plus lent. Dans la suite, les programmes dont je parle sont codés sans charger le fichier en mémoire.

    - Le problème est bien plus bizarre que ça. J'ai essayé le code sur mon ordinateur, sur mon Linux, une image de 640x480 toute grise (qui fait 3.7 Mo) se assez vite en 0.3 seconde.
    Par contre, quand je compile sous mon Windows XP avec Visual C++ 2005 (et le même PC exactement) là l'image est bien chargée en 3 secondes. Jouer sur les optimisations ne change rien. C'est marrant qu'il y ait une différence d'un ordre de grandeur !

    Des idées sur ça ? Vous avez déjà rencontré et résolu un problème du genre ?

  10. #10
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    je viens de rencontrer exactement ce problème: sous xp Visual 2005, environ 1.29 s sans buffer, 1.38 avec, sous gcc4.3.2 et ubuntu, 215ms sans et 185ms pour la même image...

    apparement, la librarie doit est mal implémentée chez microsoft.... à tel point que c'est plus lent avec le buffer...

    sinon, existe-t'il d'autres librairies de traitement de texte équivalente ? (peut-être avec boost:: regex...)
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  11. #11
    Invité
    Invité(e)
    Par défaut
    Pour garder les ifstream, peut etre faudrait il essayer des fonctions de lecture directe, quelque chose comme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    ifstream fdat(nom.c_str());
    char ch[4096]; 
    // ou un chiffre assez grand pour contenir la plus grande ligne
    fdat.getline(ch,4096);
    while(!fdat.eof()) {
       // lecture de la ligne
       fdat.getline(ch,4096);
    }
    fdat.close();
    Plus rapide encore, il y aurait les lectures en mode binaire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    ifstream fdat(nom.c_str(),ios::binary);
    fdat.seekg(0,ios::end);
    int len=fdat.tellg();
    fdat.seekg(0,ios::beg);
    char *ch=new char[len];
    fdat.read(ch,len);
    fdat.close();
     
    // lecture du fichier...
     
    delete[] ch;
    ou, si le fichier est gros, des lectures partielles (on lit les len octets en plusieurs fois).

    Sous Windows, encore plus vite, il y a les file mapping, ceux la te renvoient un pointeur (comme le ch au dessus, sur le fichier tout entier). Sur des fichiers de données que 100 Mo ou plus, c'est à peu près imbattable (mais complètement pas portable...)

    Voila, moi je laisserais tomber les E/S formatées, c'est fait pour de tout petits fichiers, dès qu'on travaille avec des données un peu grosses, il vaut mieux considérer la lecture comme une procédure 'bas niveau' non portable...

    Francois
    Dernière modification par Invité ; 12/05/2009 à 14h57.

  12. #12
    Membre éclairé Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Points : 871
    Points
    871
    Par défaut
    T'as pas honte de déterrer un vieux topic comme ça ?

    A part ça, moui, faudrait tester, mais j'pense pas avoir le temps pour l'instant.

  13. #13
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    Citation Envoyé par HanLee Voir le message
    T'as pas honte de déterrer un vieux topic comme ça ?

    A part ça, moui, faudrait tester, mais j'pense pas avoir le temps pour l'instant.
    Au moins, ça prouve que j'ai fait une recherche moi ! et puis, c'est mieux que d'en créer un nouveau non ?

    bon, je teste actuellement avec boost regex, sinon, tant pis, je leur dirais d'utiliser linux
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  14. #14
    Membre éclairé Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Points : 871
    Points
    871
    Par défaut
    Ah oui, ce serait bien d'essayer aussi avec Visual 2008 pour voir s'ils ont changé quelque chose.

  15. #15
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par méphistopheles Voir le message
    puis, c'est mieux que d'en créer un nouveau non ?
    Pour être franc : non. On recommande d'en créer un nouveau et de faire référence à celui-ci.

  16. #16
    Nouveau membre du Club
    Inscrit en
    Juillet 2008
    Messages
    33
    Détails du profil
    Informations forums :
    Inscription : Juillet 2008
    Messages : 33
    Points : 28
    Points
    28
    Par défaut
    peut être mettre visual studio en mode release et pas debug

Discussions similaires

  1. Repétition lecture formaté ifstream.
    Par Antares38 dans le forum SL & STL
    Réponses: 4
    Dernier message: 22/01/2010, 11h43
  2. [SL] std::ifstream vers FILE
    Par yan dans le forum SL & STL
    Réponses: 2
    Dernier message: 07/08/2007, 16h08
  3. [win2003 std]Apply Personnal settings LENT !
    Par ChristopheOce dans le forum Windows Serveur
    Réponses: 2
    Dernier message: 14/05/2007, 12h48
  4. Ifstream > Lecture d'un fichier > Format
    Par Zenol dans le forum SL & STL
    Réponses: 15
    Dernier message: 19/12/2005, 11h04
  5. Réponses: 4
    Dernier message: 04/11/2005, 09h04

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