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

Langage Delphi Discussion :

Résultats Live d'une boucle FOR


Sujet :

Langage Delphi

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 31
    Points : 20
    Points
    20
    Par défaut Résultats Live d'une boucle FOR
    Salut tlm,

    J'ai fait un programme qui me sert en fait de simulateur pour des calculs en astrophysique. Il y a un des calculs qui est une boucle FOR qui prend une éternité à se compléter même réduite à son minimum. Les résultats de chaques boucles sont ajoutés à une Listbox. J'aimerais donc savoir s'il serait possible de voir s'ajouter les résultat de ma boucle FOR au fur et à mesure qu'ils sont calculés (à la fin de chaque boucle) et non devoir attendre à la fin de la boucle FOR en entier pour pouvoir voir les 5 millions de résultats?

    Merci bcp

  2. #2
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 824
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 824
    Points : 15 249
    Points
    15 249
    Par défaut
    En rajoutant "Application.ProcessMessages;" dans la boucle, ou "TaListBox.Update;", peut-être (on en a causé récemment ici).
    Mais ça :
    (à la fin de chaque boucle) et non devoir attendre à la fin de la boucle
    c'est pas clair / pas cohérent... Ou il y a 2 boucles imbriquées ? Ce qui ne change rien à ma soluce.
    Mes 2 cts,
    --
    jp
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  3. #3
    Membre régulier
    Inscrit en
    Janvier 2005
    Messages
    103
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 103
    Points : 97
    Points
    97
    Par défaut
    Tu peux aussi utiliser un thread pour ton calcul, ce qui permettra d'éviter de "freezer" ton application et de suivre l'avancement en temps réel.

  4. #4
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Salut,

    Il y a un des calculs qui est une boucle FOR qui prend une éternité à se compléter même réduite à son minimum. Les résultats de chaques boucles sont ajoutés à une Listbox. J'aimerais donc savoir s'il serait possible de voir s'ajouter les résultat de ma boucle FOR au fur et à mesure qu'ils sont calculés (à la fin de chaque boucle) et non devoir attendre à la fin de la boucle FOR en entier pour pouvoir voir les 5 millions de résultats?
    1) "Eternité" : C'est pas étonnant si ta boucle de 5 millions de résultats prend une éternité vu qu'elle est brigrement ralentie par les ajouts dans ta ListBox d'affichage et ceci est vrai pour tous les composants d'affichage utilisés dans une boucle. A titre d'exemple, dans cette discussion : http://www.developpez.net/forums/sho...=462546&page=2 la suppression d'un simple caption:=timetostr(time-t); d'affichage du temps qui s'écoulait pendant le traitement d'une image de 200 x 200 pixels a permis de descendre de 24 à 4 secondes.

    Suggestion 1: Ne pas alimenter la ListBox pendant les calculs, préférer ajouter les résultats dans un Stream lors des calculs et dès que les calculs sont achevés tu fais un listbox1.Items.LoadFromStream(monStream) final pour alimenter la ListBox en un seul bloc c'est bigrement plus rapide.

    A titre d'exemple, voici une discussion :http://www.developpez.net/forums/sho...d.php?t=467303
    où le chargement d'un RichEdit avec un fichier d'1,4 Mo contenu dans une StringList mettait (avec des Add dans une boucle) initialement presque 60 mn et qui grâce à un Stream intermédiaire a permis de descendre à 2mn 50.

    2) A propos de "savoir s'il serait possible de voir s'ajouter les résultat de ma boucle FOR au fur et à mesure qu'ils sont calculés" : C'est possible mais d'une part ça rallonge l'"éternité" de ta boucle et en plus les résultats risquent de s'afficher à une vitesse qui empêche de les lire.

    Suggestion 2: si tu veux vraiment voir que les calculs avancent sans trop ralentir ton schmilblic utilises un If (IndiceBoucle mod 10000)=0 then begin Label1.caption:=StringResultat; Label1.UpDate; end; pour afficher de temps en temps un résultat lisible sans trop ralentir les calculs (1 résultat sur 10000 dans cet exemple, à modifier selon tests)

    A+

    EDIT : Ajout du lien vers la discussion en rapport avec les performances du LoadFromStream(monStream)
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  5. #5
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Commence avant tout par encadrer ta boucle de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ListBox1.Items.BeginUpdate;
    try
      // ta boucle
    finally
      ListBox1.Items.EndUpdate;
    end;
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  6. #6
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    Accoustic a écrit : Les résultats de chaque boucle sont ajoutés à une Listbox.
    ...
    voir les 5 millions de résultats
    ... Y'a un truc qui m'intrigue : Ayant voulu faire quelques tests comparatifs de vitesse j'ai initialisé ma ListBox avec ListBox2.Items.Capacity:=5000000;
    mais en cours d'exécution j'ai le message "impossible d'insérer une ligne" qui surgit après la ligne dont l'indice est seulement de 32735

    On fait comment pour caser 5 millions de résultats dans un TListBox si on veut un TListBox et non un TRichEdit ?

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  7. #7
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    En attendant de savoir comment faire pour caser 5 millions de résultats dans un TListBox j'ai fait des tests comparatifs avec un RichEdit où faute de mem-vive-disponible suffisante j'ai du plafonner les tests à 214621 lignes de 30 caractères + les #13#10 et au-lieu de mesurer uniquement les temps-mis je quitte les boucles au bout de 30 secondes pour afficher le nombre de lignes qui ont pu être traitées le code utilisé à cet effet est le suivant :
    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
     
    const     ItemsCount = 214621; //< valeur limite because mem-vive-dispo insuffisante pour 5 millions de résultats
              lgLig      = 30;    // nombre de caractères par ligne
              DureeMax   = 30000; // soit 30 secondes
    var       Start : DWord;
     
    function  Resu(i, lgLig : integer) : string;
    var       s : string;
    begin     s:=intToStr(i)+' ';
              Result:=s+StringOfChar('8',LgLig - length(s));
    end;
     
    //        Impact d'un label4.Caption:= dans une boucle de RichEdit.lines.Add
    procedure TfrmGenP.btnBoucleAddAvecSansLabelClick(Sender: TObject);
    var       i : integer;
    begin     //RE1.Lines.Capacity:=ItemsCount;
              RE1.MaxLength := $7FFFFFF0; // RE1 = RichEdit
              RE1.clear;
              RE1.Update;
              Start:=GetTickCount;
              i:=-1;
              try
                  repeat inc(i);
                         RE1.Lines.Add(Resu(i,lgLig));
                         //label4.Caption:=IntToStr(i);
                         //label4.Update;
                  until (GetTickCount-Start >= DureeMax) or (i=ItemsCount-1)
              Finally
                  Edit2.text:='Pour durée max = '+intToStr(DureeMax)+' ms traité '+intToStr(i)+' lignes '+intToStr(GetTickCount-Start)+' ms';
                  //Avec RichEdit et :
                  //- avec label4.Caption et Pour durée max = 30000 ms traité 7919 lignes
                  //- sans label4.Caption et Pour durée max = 30000 ms traité 12379 lignes
              end;
    end;
     
    //            Intérêt du BeginUpdate et du EndUpdate :
    procedure TfrmGenP.btnBoucleAddEtUpdatesClick(Sender: TObject);
    var       i : integer;
    begin     //RE1.Lines.Capacity:=ItemsCount;
              RE1.MaxLength := $7FFFFFF0;
              Start:=GetTickCount;
              RE1.clear;
              RE1.Lines.BeginUpdate;
              i:=-1;
              try repeat inc(i);
                         RE1.Lines.Add(Resu(i,lgLig));
                  until (GetTickCount-Start >= DureeMax) or (i=ItemsCount-1)
              finally
                  RE1.Lines.EndUpdate;
                  Edit2.text:='Pour durée max = '+intToStr(DureeMax)+' ms traité '+intToStr(i)+' lignes '+intToStr(GetTickCount-Start)+' ms';
                  // Pour durée max = 30000 ms traité 13355 lignes
              end;
    end;
     
    //            Intérêt de passer par un MemoryStream: 
    procedure TfrmGenP.btnAvecMemStreamClick(Sender: TObject);
    var       i : integer; MS : TMemoryStream;
    begin     //RE1.Lines.Capacty:=ItemsCount;
              RE1.MaxLength := $7FFFFFF0;
     
              Start:=GetTickCount;
              RE1.clear;
              RE1.Update;
              //RE1.Lines.BeginUpdate;  //< sans intérêt avec MemoryStream
              MS := TMemoryStream.Create;
              i:=-1;
              try repeat inc(i);
                         MS.Write(PChar(Resu(i,lgLig)+#13#10)^,LgLig+2);
                  until (GetTickCount-Start >= DureeMax) or (i=ItemsCount-1);
                  MS.Position:=0;
                  RE1.Lines.LoadFromStream(MS);
              finally
                  //RE1.Lines.EndUpdate;
                  Edit2.text:='Pour durée max = '+intToStr(DureeMax)+' ms traité '+intToStr(i)+' lignes '+intToStr(GetTickCount-Start)+' ms';
                  MS.Free;
                  //- sans BeginUpdate, Pour durée max = 30000 ms traité 214621 lignes 14731 ms
                  //- avec BeginUpdate, Pour durée max = 30000 ms traité 214621 lignes 14683 ms
              end;
    end;
     
    procedure TfrmGenP.FormShow(Sender: TObject);
    begin     RE1.lines.add(fGoMoKo(memDispo)); // mem vive libre
     
    end;
    Résultats des tests de chargement du RichEdit avec Pentium III à 1,13 GHz :

    1) Impact d'un label4.Caption:= dans une boucle de RichEdit.lines.Add :
    1.1) sans label4.Caption et Pour durée max = 30000 ms traité 12379 lignes
    1.2) avec label4.Caption et Pour durée max = 30000 ms traité 7919 lignes soit 1,56 fois plus lent

    2) Intérêt du BeginUpdate et du EndUpdate avec RichEdit.lines.Add :
    Pour durée max = 30000 ms traité 13355 lignes, soit 1,08 fois plus rapide que 1.1

    3) Intérêt de charger les résultats dans un MemoryStream puis de transférer celui-ci dans le RicheDit avec un LoadFromStream :
    3.1) - sans BeginUpdate, Pour durée max = 30000 ms traité 214621 lignes mais exit boucle après 14731 ms vu que 214621=limite pour mem-vive-dispo
    3.2) - avec BeginUpdate, Pour durée max = 30000 ms traité 214621 lignes mais exit boucle après 14683 ms vu que 214621=limite pour mem-vive-dispo.

    ... donc en moins de 15 sec avec un MemoryStream on charge 16 fois plus de lignes que dans le cas des 30 sec avec BeginUpdate + EndUpdate + RichEdit.lines.Add
    ... et donc pour la rapidité y'a pas photo le MemoryStream est bigrement plus rapide mais avec l'inconvénient d'occuper de la place en mémoire en sus de celle occupée par le RichEdit.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  8. #8
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut Résultats d'un test supplémentaire avec TFileStream
    Bonjour,

    Pour compléter les tests de mon message précédent j'en ai fait un autre où les résultats sont transférés dans un FileStream (pour réduire l'occupation de mem-vive) avant de charger le RichEdit en bloc avec un LoadFromStream
    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
    //        Intérêt de passer par un FileStream pour accéler le chargement d''un RichEdit
    procedure TfrmGenP.btnAvecFileStreamClick(Sender: TObject);
    var       i : integer; FS : TFileStream;
    begin     RE1.MaxLength := $7FFFFFF0;
              Start:=GetTickCount;
              RE1.clear;
              RE1.Update;
              FS := TFileStream.Create(RepAppli+'AFS.txt',fmCreate);
              i:=-1;
              //RE1.Lines.BeginUpdate; < sans intérêt avec FileStream
              try repeat inc(i);
                         FS.Write(PChar(Resu(i,lgLig)+#13#10)^,LgLig+2);
                  until (GetTickCount-Start >= DureeMax) or (i=ItemsCount-1);
                  FS.Position:=0;
                  RE1.Lines.LoadFromStream(FS);
              finally
                  //RE1.Lines.EndUpdate;
                  Edit2.text:='Pour durée max = '+intToStr(DureeMax)+' ms traité '+intToStr(i+1)+' lignes '+intToStr(GetTickCount-Start)+' ms';
                  FS.Free;
                  //Pour durée max = 30000 ms traité 214621 lignes mais exit boucle sur ItemsCount=214621 après 9624 ms
                  //Pour durée max = 30000 ms traité 293063 lignes avec ItemsCount=293063
              end;
    end;
    Résultats des tests de chargement du RichEdit avec FileStream, même Pentium III à 1,13 GHz :

    4.1) Pour durée max = 30000 ms traité 214621 lignes mais exit boucle sur ItemsCount=214621 après 9624 ms soit 1,53 fois plus rapide que les 14731 ms obtenus hier avec le MemoryStream avec en prime l'économie de mémoire dû à FileStream

    4.2) Pour durée max = 30000 ms traité 293063 lignes avec ItemsCount=293063, alors qu'avec le MemoryStream ma mem-vive-dispo me limitait à 214621 lignes.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

Discussions similaires

  1. Réponses: 2
    Dernier message: 10/10/2014, 17h02
  2. Sauvegarde de résultats dans une boucle FOR-END
    Par laroche1 dans le forum MATLAB
    Réponses: 4
    Dernier message: 19/12/2007, 16h51
  3. Problème avec une DLL dans une boucle For
    Par BraDim dans le forum Langage
    Réponses: 5
    Dernier message: 20/09/2005, 12h22
  4. [batch] incrémentation dans une boucle for
    Par bart64 dans le forum Scripts/Batch
    Réponses: 4
    Dernier message: 08/09/2004, 20h05
  5. Réponses: 3
    Dernier message: 06/07/2004, 10h21

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