Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

performance de lecture de fichiers formatés

37 réponses
Avatar
Ploc
Bonjour,

j'ai un fichier du style :

label 2.3 4.5 5.6
label2 1.2 1.0 -2.
...


qui est assez gros (près d'1 Go).

J'avais un programme C à base de fscanf.
En passant de C (à base de fscanf) à c++ avec ifstream (voir le code en
bas), je passe de 1min 40s en C à 3min 10s en c++.

Je trouve que ca fait un gap quand même.
Comme je n'ai pas trop d'expérience sur les fichiers en c++, je m'en
remets à vous.

Vous pouvez me dire si vous voyez des choses à améliorer pour avoir de
meilleures performances (plus proches du C)?

Je joins un bout de code avec uniquement la lecture du fichier et
l'extraction des données.
Le code C fait la même chose mais avec fscanf et feof. Je peux le donner
si ca peut aider.


#include <iostream>
#include <fstream>

using namespace std;

int main(int argc, char ** argv)
{
ifstream ifs("fichier.toto");

float x,y,z;
string lc;

int count =0;
int i;
while (! ifs.eof())
{
ifs >> lc>>x>>y>>z;
if (!ifs.eof())
{
count ++;
}
}
cout <<"count = "<<count<<endl;

return 0;
}


Merci d'avance.

Ploc.

7 réponses

1 2 3 4
Avatar
James Kanze
On May 3, 9:46 pm, Ploc wrote:
j'ai un fichier du style :

label 2.3 4.5 5.6
label2 1.2 1.0 -2.
...

qui est assez gros (près d'1 Go).

J'avais un programme C à base de fscanf. En passant de C (à
base de fscanf) à c++ avec ifstream (voir le code en bas), je
passe de 1min 40s en C à 3min 10s en c++. Je trouve que ca
fait un gap quand même. Comme je n'ai pas trop d'expérience
sur les fichiers en c++, je m'en remets à vous.

Vous pouvez me dire si vous voyez des choses à améliorer pour
avoir de meilleures performances (plus proches du C)?

Je joins un bout de code avec uniquement la lecture du fichier
et l'extraction des données. Le code C fait la même chose
mais avec fscanf et feof.


Je doute que la reste du code est identique, parce que....

Je peux le donner si ca peut aider.

#include <iostream>
#include <fstream>

using namespace std;

int main(int argc, char ** argv)
{
ifstream ifs("fichier.toto");

float x,y,z;
string lc;


Tu ne peux pas lire un std::string avec fscanf. Il y a donc des
allocations dynamiques (probablement) ici que tu n'as pas dans
l'autre. Ce qui peut faire une différence.

(Aussi, en passant, tu n'as pas inclu <string>. L'utilisation de
std::string est donc un comportement indéfini. Mais ce n'est
certainement pas la raison de ton problème de performance.)

int count =0;
int i;
while (! ifs.eof())
{
ifs >> lc>>x>>y>>z;


Aussi : pourquoi pas simplement :

while ( ifs >> lc >> x >> y >> z ) ...

C'est nettement plus idiomatique.

if (!ifs.eof())
{
count ++;
}
}
cout <<"count = "<<count<<endl;

return 0;
}


Selon les implémentations, il peut y avoir plus ou moins de
différences de performances entre iostream et FILE*. En général,
en faveur des FILE* (mais ce n'est pas forcement universel). Une
partie des différences, en revanche, c'est qu'on a une tendance
à utiliser des idiomes plus sûrs avec iostream, de lire dans un
std::string, par exemple, plutôt que dans un char[].

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Fabien LE LEZ
On Mon, 5 May 2008 02:42:08 -0700 (PDT), James Kanze
:

Selon les implémentations, il peut y avoir plus ou moins de
différences de performances entre iostream et FILE*. En général,
en faveur des FILE* (mais ce n'est pas forcement universel).


Ce que je ne comprends pas, c'est pourquoi mon implémentation
(bricolée en quelques minutes) est très largement plus rapide que
"operator >> (istream&, double&)".
D'autant que je commence par lire une ligne dans un string avec
getline(), puis je parse cette chaîne (en faisant les vérifications
qui vont bien), alors que operator>> ne passe pas par cette étape
intermédiaire.

Comme je ne pense pas être meilleur que les auteurs de g++ dans leur
propre domaine, je me doute qu'il y a une explication quelque part,
mais je ne vois pas où. Et on ne parle pas ici de quelques % de
différence, mais bien d'un facteur 4 (grosso modo).

Avatar
Michael DOUBEZ
On Mon, 5 May 2008 02:42:08 -0700 (PDT), James Kanze
:

Selon les implémentations, il peut y avoir plus ou moins de
différences de performances entre iostream et FILE*. En général,
en faveur des FILE* (mais ce n'est pas forcement universel).


Ce que je ne comprends pas, c'est pourquoi mon implémentation
(bricolée en quelques minutes) est très largement plus rapide que
"operator >> (istream&, double&)".
D'autant que je commence par lire une ligne dans un string avec
getline(), puis je parse cette chaîne (en faisant les vérifications
qui vont bien), alors que operator>> ne passe pas par cette étape
intermédiaire.


Peut être l'indirection causée par le codecvt. Ton code ne prends pas en
compte la localisation bien que ça n'explique pas un facteur 4.

Comme je ne pense pas être meilleur que les auteurs de g++ dans leur
propre domaine, je me doute qu'il y a une explication quelque part,
mais je ne vois pas où. Et on ne parle pas ici de quelques % de
différence, mais bien d'un facteur 4 (grosso modo).


Ou peut être il n'y a pas eu d'effort de la part des auteurs de g++ pour
optimiser iostream.

D'après B.Stroustrup, iostream est plus rapide (en théorie)
http://www.research.att.com/~bs/new_learning.pdf.

Michael


Avatar
James Kanze
On May 5, 6:20 pm, Fabien LE LEZ wrote:
On Mon, 5 May 2008 02:42:08 -0700 (PDT), James Kanze
:

Selon les implémentations, il peut y avoir plus ou moins de
différences de performances entre iostream et FILE*. En général,
en faveur des FILE* (mais ce n'est pas forcement universel).


Ce que je ne comprends pas, c'est pourquoi mon implémentation
(bricolée en quelques minutes) est très largement plus rapide que
"operator >> (istream&, double&)".
D'autant que je commence par lire une ligne dans un string avec
getline(), puis je parse cette chaîne (en faisant les vérifications
qui vont bien), alors que operator>> ne passe pas par cette étape
intermédiaire.

Comme je ne pense pas être meilleur que les auteurs de g++ dans leur
propre domaine, je me doute qu'il y a une explication quelque part,
mais je ne vois pas où. Et on ne parle pas ici de quelques % de
différence, mais bien d'un facteur 4 (grosso modo).


Est-ce que tu es sûr que ton implémentation est 100% correcte,
dans tous les cas ? Entre les options de formattage et les
problèmes d'arrondi (voir "How to read floating point numbers
accurately", de William Clinger,
http://portal.acm.org/citation.cfm?id“557), il y a pas mal de
choses qui peuvent rendre une implémentation « correcte »
nettement moins rapide qu'une à peu près correcte. (Évidemment,
l'arithmétique entière à 64 bits, ce qui est universalement
disponible aujourd'hui, simplifie déjà beaucoup.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
James Kanze
On May 6, 9:23 am, Michael DOUBEZ wrote:

On Mon, 5 May 2008 02:42:08 -0700 (PDT), James Kanze
:

Selon les implémentations, il peut y avoir plus ou moins de
différences de performances entre iostream et FILE*. En général,
en faveur des FILE* (mais ce n'est pas forcement universel).


Ce que je ne comprends pas, c'est pourquoi mon
implémentation (bricolée en quelques minutes) est très
largement plus rapide que "operator >> (istream&, double&)".
D'autant que je commence par lire une ligne dans un string
avec getline(), puis je parse cette chaîne (en faisant les
vérifications qui vont bien), alors que operator>> ne passe
pas par cette étape intermédiaire.


Peut être l'indirection causée par le codecvt. Ton code ne
prends pas en compte la localisation bien que ça n'explique
pas un facteur 4.


La localisation coûte cher dans std::filebuf. Ailleurs, ça
dépend; d'après ce qu'on m'a dit, c'est possible d'en minimiser
le coût. (Au moins une personne m'a dit la même chose pour
std::filebuf. Mais il avoue que c'est assez compliqué, et que
les implémentations aujourd'hui ne le font pas.)

Comme je ne pense pas être meilleur que les auteurs de g++
dans leur propre domaine, je me doute qu'il y a une
explication quelque part, mais je ne vois pas où. Et on ne
parle pas ici de quelques % de différence, mais bien d'un
facteur 4 (grosso modo).


Ou peut être il n'y a pas eu d'effort de la part des auteurs
de g++ pour optimiser iostream.

D'après B.Stroustrup, iostream est plus rapide (en
théorie)http://www.research.att.com/~bs/new_learning.pdf.


Attention. La date sur cet article est 1999. Ce qui fait penser
qu'il parle des iostream classique, et non des iostream
standard. La gestion de la facette codecvt dans filebuf rend
l'optimisation nettement plus difficile.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
Fabien LE LEZ
On Tue, 6 May 2008 01:35:27 -0700 (PDT), James Kanze
:

Est-ce que tu es sûr que ton implémentation est 100% correcte,
dans tous les cas ?


Effectivement, c'est probablement là l'explication.

Avatar
loic.actarus.joly
On 6 mai, 13:38, James Kanze wrote:
La localisation coûte cher dans std::filebuf. Ailleurs, ça
dépend; d'après ce qu'on m'a dit, c'est possible d'en minimiser
le coût. (Au moins une personne m'a dit la même chose pour
std::filebuf. Mais il avoue que c'est assez compliqué, et que
les implémentations aujourd'hui ne le font pas.)


Il y a eu un débat récemment là dessus sur les ML C++, sans pour
autant qu'un consensus clair se dégage à mon avis.

Je serais curieux de voir ce que donne le programme par exemple avec
les fastreams : http://www.msobczak.com/prog/fastreams/

1 2 3 4