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

Delphi Discussion :

Manipulations de millions de chaines et de milliers de fichiers


Sujet :

Delphi

  1. #21
    Membre actif Avatar de lun4t1k
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    276
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 276
    Points : 274
    Points
    274
    Par défaut
    Gilbert Geyer
    TFileStream : y'a presque rien en mémoire,
    Ou ca va alors? L'interet de la mem vive est la rapidite. Mais la saturation est vite arrivée.

    à première vue ça semble compliqué juste pour y stocker temporairement des combinaisons. Si t'as besoin d'accumuler temporairement des combinaisons qui forment des string tu peux utiliser des StringList c'est vachement souple d'utilisation :
    La je pensais associé a mon tab un TFileStream. Il n'ya pas une méthode qui permet simplement d'ajouter une string au stream?
    Je ne vois pas l'interet de mettre en plein milieu un StringList.
    A moins que tu me conseille d associer a chaque clé une StringList qui contient ma combi, de l'écrire dans le flux et d'écrire le flux ds un fichier?
    Ca rajoute une étape?


    PS: C'est pareil! au fur et a mesure que je tape, yen a d'autres qui arrivent, c'est génial ca me permet de prcéiser le tout.

  2. #22
    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
    TFileStream : y'a presque rien en mémoire,
    Ou ca va alors?
    ... ça va rapidement sur le disque, et c'est nettement plus rapide quand y envoie un buffer de taille conséquente ( monStream2.write(const Buffer; Count: Longint): Longint et moi je mets fréquemment au moins un buff : array [0..4096] of char; ) plutôt que d'y envoyer un caractère après l'autre ce qui ralentit forcément.

    Il n'ya pas une méthode qui permet simplement d'ajouter une string au stream?
    ... si, si :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     monFileStream.Write(PChar(maChaine)^, length(maChaine));
    Je ne vois pas l'interet de mettre en plein milieu un StringList.
    A moins que tu me conseille d associer a chaque clé une StringList qui contient ma combi, de l'écrire dans le flux et d'écrire le flux ds un fichier?
    Ca rajoute une étape?
    ... j'avais cité les StringList par opposition à ce que j'ai vu en cliquant sur ton lien "Tab Assoc".
    ... mais si tu n'as pas besoin d'accumuler tes chaines dans un truc intermédaire tu peux les envoyer une à une dans le FileStream.
    ... par contre plus le buffer du write est rempli mieux ça vaut pour la vitesse
    ... au lieu de StringList et plutôt que d'envoyer des chaines courtes tu peux, si ta logique le permet, concaténer plusieurs combinaisons en une seule chaine du style maChaine := combi1 +#13#10 +combi2 +#13#10 +combi3 +#13#10+ etc de façon à remplir le buffer à raz-bord à chaque fois.
    A +

  3. #23
    Membre actif Avatar de lun4t1k
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    276
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 276
    Points : 274
    Points
    274
    Par défaut
    Citation Envoyé par Gilbert Geyer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     monFileStream.Write(PChar(maChaine)^, length(maChaine));
    Arf j'ai pas encore vu les pointeurs! lol


    Citation Envoyé par Gilbert Geyer
    ... j'avais cité les StringList par opposition à ce que j'ai vu en cliquant sur ton lien "Tab Assoc".
    ... mais si tu n'as pas besoin d'accumuler tes chaines dans un truc intermédaire tu peux les envoyer une à une dans le FileStream.
    ... par contre plus le buffer du write est rempli mieux ça vaut pour la vitesse
    ... au lieu de StringList et plutôt que d'envoyer des chaines courtes tu peux, si ta logique le permet, concaténer plusieurs combinaisons en une seule chaine du style maChaine := combi1 +#13#10 +combi2 +#13#10 +combi3 +#13#10+ etc de façon à remplir le buffer à raz-bord à chaque fois.
    A +
    Tant qu'a faire, j'associe a chaque clé un string que je remplit, et a la fin j enregistre ds le fichier.
    C'est une approche similaire au TStringList. Ca evite d'écrire ligne par ligne dans le stream et de n'écrire qu'un buffer complet. Par contre je ne sais pas si je peux vraiment blinder mon buffer...genre entre 5 et 10 000 combi par fichier? donc 5 et 10 000 combi dans la chaine.
    L'écriture du buffer risque d'en etre ralentie.

  4. #24
    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
    Arf j'ai pas encore vu les pointeurs! lol
    ... si c'est juste pour envoyer var maChaine : string; dans le FileStream avec monFileStream.Write(PChar(maChaine)^, length(maChaine)); t'as pas besoin de voir les pointeurs juste pour recopier cette ligne de code.

    J'en profite pour une petite rectif : comme maChaine := combi1 +#13#10 +combi2 +#13#10 +combi3 +#13#10+ etc c'est justement la chaine citée ci-dessus pas besoin de buffer intermédiaire, c'est le PChar()^ qui fait office de buffer dans ce cas.

    Juste pour un exemple : voiçi un bout de code où je crée un fichier à contenu aléatoire dont chaque chaine nommée LigAl est ajoutée au fichier avec FS.Write(PChar(LigAl)^, length(LigAl)); :


    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
    procedure TfrmGen.bCreerFichierAleatoireClick(Sender: TObject);
    label     PasBon;
    var       FS : TFileStream; NomFichier,sTailleMo,LigAl,invite : string;
              TailleOc,code,numLig : integer; 
     
              function LgAleat : integer; // Longueur Aléatoire
              begin    Result:=Random(98); end;
     
              function LigneAleat(Lg : integer) : string; // Texte Aléatoire
              var      i : integer;
              begin    Result:='';
                       for i:=1 to Lg
                       do Result:=Result + chr(67 +Random(26));
              end;
     
    begin     NomFichier:=edNomFichier.text;
              if FileExists(NomFichier)
              then begin sms(NomFichier+' : Existe déjà. Autre nom'); EXIT; end;
              FS := TFileStream.Create(NomFichier, fmCreate);
              invite := 'Entrer sa taille en Mo : ';
            PasBon :
              sTailleMo:= InputBox('Créer Fichier Aleatoire + Doublons', invite, '');
              val(sTailleMo,TailleOc,code);
              if code<>0 then
              begin invite:='... taille en Mo = valeur entière :'; goto PasBon; end;
              TailleOc := TailleOc*1024*1024;
              Randomize;
              numLig:=0;
              repeat inc(numLig);
                     LigAl:=LigneAleat(LgAleat);
                     // Eviter génération de profusion de doublons avec chaines très courtes
                     if (length(ligAl)>0) and (length(ligAl)<=3)
                     then LigAl:=LigAl+intToStr(numLig);
                     LigAl:=LigAl+#13#10;
                     FS.Write(PChar(LigAl)^, length(LigAl));
              until FS.Size >= TailleOc;
              LigAl:='ANAGRAMME'+#13#10;
              FS.Write(PChar(LigAl)^, length(LigAl));
              LigAl:='EMMARGANA'+#13#10;
              FS.Write(PChar(LigAl)^, length(LigAl));
              LigAl:='<<< MI-DOUBLON >>>'+#13#10;
              FS.Write(PChar(LigAl)^, length(LigAl));
              FS.Write(PChar(LigAl)^, length(LigAl));
              FS.Free;
    end;
    A +

  5. #25
    Membre actif Avatar de lun4t1k
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    276
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 276
    Points : 274
    Points
    274
    Par défaut
    Par contre la je bug:
    Mon tab assoc est maintenant <string,string>. Je concatene les combis au fur et a mesure.

    Enregistrement de la valeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    name := 'output/' + dizaine + '-' + unite + '.txt';
     
      //Ecrire le string correspondant
      t[name] := t[name] + Chaine;
    Et je parcours mon tab assoc pour écrire dans les fichiers:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
                name := 'output/' + propr1 + '-' + propr2 + '.txt';
                FT := TFileStream.Create(name, fmOpenWrite or fmCreate);
     
                try
                    contenu := t.Valeur[name]; // ou contenu := t[name];
                    taille := Length(contenu);
                    FT.Write(taille, SizeOf(taille));
                    FT.Write(contenu[1], taille);
                    Memo2.Lines.Add(IntToStr(I) + '-' + IntToStr(J) + '-> ' + contenu[1]);
                finally
                    FT.Free;
                end;
    Le contenu enregistré contient des caractères non imprimables au debut.
    Le reste est normal...
    merci de votre aide!

    EDIT: Je vais donc ecrire dans mon buffer une grosse chaine de caracteres avec parfois plus de 10000 combis. y a -til un moyen de voir la progression de cet écriture et de la modéliser avec une progress bar par exemple?
    Je peux aussi incrementer un compteur dans ma boucle mais bon...

  6. #26
    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,

    Le contenu enregistré contient des caractères non imprimables au debut.
    Le reste est normal...
    ... le début correspond à FT.Write(taille, SizeOf(taille)) et "taille" est un integer alors que reste c'est du texte : ne pas mélanger des types différents dans un fichier .txt comme on le fait avec des fichiers .dat.
    ... si tu veux que "taille" soit en caractères imprimables il faut convertir "taille" en string : sTaille:=intToStr(taille) puis l'ajouter au Stream avec FT.Write(PChar(sTaille)^, length(sTaille));

    EDIT: Je vais donc ecrire dans mon buffer une grosse chaine de caracteres avec parfois plus de 10000 combis. y a -til un moyen de voir la progression de cet écriture et de la modéliser avec une progress bar par exemple?
    Je peux aussi incrementer un compteur dans ma boucle mais bon...
    ... "buffer" : pour faire FT.Write(PChar(maGrosseChaine )^, length(maGrosseChaine)) pas besoin de passer par un buffer qu'il faudrait dimensionner.
    ... "voir la progression" : bien sûr, c'est possible, si c'est vraiment utile ce qui dépend de la vitesse à laquelle les 10000 combi sont générées.
    ... dans pas mal de cas l'affichage d'un compteur avec un if (compteur mod 1000=0) then label1.caption:=intToStr(compteur)+'/'+intToStr(countMax); label1.upDate; par exemple peut suffire sans que cet affichage ne ralentisse trop la boucle ... mais rien n'interdit d'utiliser une ProgressBar entre 0 et countMax sauf si countMax n'est pas connu à l'avance et dans ce cas faut se contenter d'un label1.caption:=intToStr(compteur);

    A+

  7. #27
    Membre actif Avatar de lun4t1k
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    276
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 276
    Points : 274
    Points
    274
    Par défaut
    J'attendais d'être chez moi pour tester, (merci de ton indication)
    Mais cela ne marche pas.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    contenu := t.Valeur[name];
    taille := Length(contenu);
    sTaille:=IntToStr(taille);
    FT.Write(PChar(sTaille)^, Length(sTaille));
    FT.Write(contenu[1], taille);
    Une idée? il m'écrit un nombre et le reste. Je veux juste lui indiquer la taille a ecrire!

    EDIT: J'ai mis :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      contenu := t.Valeur[name];
                taille := Length(contenu);
                FT.Write(contenu[1], taille);
    mais ca me saute une ligne en debut de fichier!

  8. #28
    Membre actif Avatar de lun4t1k
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    276
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 276
    Points : 274
    Points
    274
    Par défaut
    Ca y est c'est bon, c'est parti mais je serai incappable de dire ce que c'était

    meric a vous

  9. #29
    Membre actif Avatar de lun4t1k
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    276
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 276
    Points : 274
    Points
    274
    Par défaut
    Voici maintenant arrivé le chapitre optimisation.
    J'utilise donc un tableau associatif <String, TFileStream>

    Une fois que j'ai ma combi je la stocke dans t[name].
    Au déut tout va bien mais a partir de 400 000 ou 500 000 combi générées, ca ralentit. A la fin de la generation, le prog utilise 200Mo de ram.
    (j'enregistre tout et j'ecrit a la fin)

    Je me dit heureusement que je n'utilise pas TMemoryReader!

    Si j'enregistre dans le fichier au bout de 20 000 combi par exemple, ca me ralentit le processus et ne m'allege pas du tout.

    Auriez vous une proposition? <String, TStringList> serait il mieux?

    Merci

  10. #30
    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,

    J'utilise donc un tableau associatif <String, TFileStream>
    Une fois que j'ai ma combi je la stocke dans t[name].
    Au déut tout va bien mais a partir de 400 000 ou 500 000 combi générées, ca ralentit. A la fin de la generation, le prog utilise 200Mo de ram.
    (j'enregistre tout et j'ecrit a la fin) ...
    Si j'enregistre dans le fichier au bout de 20 000 combi par exemple, ca me ralentit le processus et ne m'allege pas du tout.
    ... comme tu as fait un "finally FT.Free; end;" en fin d'enregistrement du fichier ce n'est certainement l'utilisation du FileStream qui en est la cause.
    ... par contre puisque tu stocke toutes tes combis dans t[name] et que l'on ne voit pas la totalité de ton code il n'est pas interdit de penser que cela pourrait venir du fait que le tableau t[name] est n'a pas été vidé de la mémoire avant d'attaquer la suite et que dans cette suite tu remplaces simplement le contenu des cases de ce tableau par un nouveau contenu.
    C'est le cas soit d'un tableau statique (var t : attay of [0..800000]) soit d'un tableau dynamique (var t : array of string) utilisé comme un tableau statique c'est à dire initialisé avec un SetLength(t,800000). Par contre l'utilisation d'un tableau dynamique remis à 1 avec SetLength(t,1) devrait dégager la mémoire et pour le ré-initialiser en vue d'y charger de nouvelles combis tu le fais suivre par un SetLength(t,800000). Surtout évites d'utilliser SetLength(t,i+1) à l'intérieur d'une boucle de 800000 ça ralentirait énormément le shmilblick.

    Extrait sec de l'Aide-Delphi : procedure SetLength(var S; NewLength: Integer);
    SetLength réalloue le tableau référencé par S avec la longueur donnée. Les éléments du tableau sont préservés, mais le contenu de l'espace nouvellement alloué est indéfini. S'il n'y a pas de mémoire suffisante pour réallouer le tableau, une exception EOutOfMemory est déclenchée
    ... mais on peut plaçer le SetLength() après un "try" pour éviter les désagréments d'une telle exception et sauver les combis vers le disque.

    Auriez vu une proposition? <String, TStringList> serait il mieux?
    ... si tu remplaces "uniquement" <String, TFileStream> par <String, TStringList> ce sera pire en termes d'occupation-mémoire car ta mémoire sera chargée avec ton tableau t[name] et en plus par ta StringList ce qui est redondant.
    ... si tu veux accumuler le maxi de combis en mémoire avant de les envoyer sur le disque il faut choisir entre <t[name] + TFileStream> et <TStringList + StringList.SaveToStream> ou <TStringList + StringList.SaveToFile> ... mais une StringList ne pourra pas forcément remplacer ton tableau associatif dont on ne voit que peu de choses dans tes bouts de code.
    A+

  11. #31
    Membre actif Avatar de lun4t1k
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    276
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 276
    Points : 274
    Points
    274
    Par défaut
    Citation Envoyé par Gilbert Geyer
    Salut,
    ... comme tu as fait un "finally FT.Free; end;" en fin d'enregistrement du fichier ce n'est certainement l'utilisation du FileStream qui en est la cause.
    ... par contre puisque tu stocke toutes tes combis dans t[name] et que l'on ne voit pas la totalité de ton code il n'est pas interdit de penser que cela pourrait venir du fait que le tableau t[name] est n'a pas été vidé de la mémoire avant d'attaquer la suite et que dans cette suite tu remplaces simplement le contenu des cases de ce tableau par un nouveau contenu.
    Je rajoute simplement chaque combinaison par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if t[name] <> '' then
          t[name] := t[name] + #13#10 + Chaine
      else
        begin
              t[name] := Chaine;
        end;
    Je suis obligé de garder chaque asociation. Donc je comprend que la mémoire augmente vite. Mais qua ca relentisse....

    Citation Envoyé par Gilbert Geyer
    C'est le cas soit d'un tableau statique (var t : attay of [0..800000]) soit d'un tableau dynamique (var t : array of string) utilisé comme un tableau statique c'est à dire initialisé avec un SetLength(t,800000). Par contre l'utilisation d'un tableau dynamique remis à 1 avec SetLength(t,1) devrait dégager la mémoire et pour le ré-initialiser en vue d'y charger de nouvelles combis tu le fais suivre par un SetLength(t,800000). Surtout évites d'utilliser SetLength(t,i+1) à l'intérieur d'une boucle de 800000 ça ralentirait énormément le shmilblick.
    Ne sachant pas combiens de combinaisons iront dans l'association t[name], je ne peux pas fixer de taille.

    Citation Envoyé par Gilbert Geyer
    ... mais on peut plaçer le SetLength() après un "try" pour éviter les désagréments d'une telle exception et sauver les combis vers le disque.

    ... si tu remplaces "uniquement" <String, TFileStream> par <String, TStringList> ce sera pire en termes d'occupation-mémoire car ta mémoire sera chargée avec ton tableau t[name] et en plus par ta StringList ce qui est redondant.
    ... si tu veux accumuler le maxi de combis en mémoire avant de les envoyer sur le disque il faut choisir entre <t[name] + TFileStream> et <TStringList + StringList.SaveToStream> ou <TStringList + StringList.SaveToFile> ... mais une StringList ne pourra pas forcément remplacer ton tableau associatif dont on ne voit que peu de choses dans tes bouts de code.
    A+
    C'est bien ce que je pensais. Mais ma mémoire sera toujours trop sollicitée.
    Je vais y rélfléchir et ferais une réponse plus...constructive que celle ci!

    merci

    EDIT : mon enregsitrment vers le fichier n'est pas long du tout.

  12. #32
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Bonjour,

    J'arrive un peu tard et j'ai lu en diagonale.
    Mais, en supposant que le programme de génération des combi fasse seulement de l'écriture et n'accéde pas aux combis déjà enregistrées, il me semble qu'il faudrait utiliser une technique de cache :
    While (not finished)
    - stocker en mémoire les combis générées jusquà ce qu'on ait atteint les limites mémoires dispo (ou un certain nombres fixe de combi),
    - "trier" les combis en fonction du fichier de destination et, en traitant une seule fois chaque fichier à mettre à jour, concaténer à chaque fichier toutes les combis associées
    end

    Au lieu du tri, on peut gérer une liste chainée avec racines multiples (une racines fixe par fichier de destination).

  13. #33
    Membre actif Avatar de lun4t1k
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    276
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 276
    Points : 274
    Points
    274
    Par défaut
    Merci de t'y interesser Graffito.

    Ton idée est intéressante, la generation se faisant rapidement, il ne me reste qu'a stocker toutes les combis (structure optimale?) et à trouver la meilleure methode de tri adapté pour le calcul de grandes données.
    Le tableau aura une taille de 2 millions a 13 millions de combinaisons.

    Sachant qu'une combinaison est un sous tableau de 5 nombres.

    Au final j'aurai toutes mes combis, je les trie par fichier de destination (meilleure complexité que l'ajout dans mon tab associatif?) et une fois trié j'écrit chaque bloc trié dans le bon fichier de destination.

    L'acces d'un tab associatif devrait etre en temps constant et l'association comprend entre 4000 et 10000 combis.

    Au final, je ne sais pas si j'y gagnerais.


    Merci

  14. #34
    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
    Re-bonjour,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    lun4t1k a écrit : Ne sachant pas combiens de combinaisons iront dans l'association t[name], je ne peux pas fixer de taille.
    ... je suppose que dans "t[name] := t[name] + #13#10 + Chaine" c'est "Chaine" qui représente une combinaison, donc ne pas confondre le nombre de combinaisons présentes dans "t[index]" avec indexMax qui est la taille du tableau "t". On parle de la même chose ?

    ... ne pourrais tu pas faire par exemple un SetLength(t,1000) en tant qu'allocation prévisionnelle de départ et surveiller un compteur pour augmenter au moment opportun la taille avec SetLength(t,2000) ... et ainsi de suite avec un pas de 1000 comme dans cet exemple ou avec un pas d'augmentation différent ???
    Avec une StringList à la place du tableau, (si le principe d'une StringList était compatible avec tes besoins) ce serait plus simple car tant qu'il y a de la mém-vive-dispo on peut faire maStringList.Add(maChaine), pas besoin du SetLength dans ce cas , suffit de mettre maStringList.Add(maChaine) après un "try".

    Je suis obligé de garder chaque asociation. Donc je comprend que la mémoire augmente vite. Mais qua ca relentisse....
    ... c'est certainement dû au fait que tu as passé le cap de la mem-vive-saturée et que Windows en arrière plan envoie l'excédent en mémoire moins vive basée sur des échanges avec le disque.

    EDIT : mon enregistrement vers le fichier n'est pas long du tout.
    ... c'est l'avantage du Stream et des StringList qui elles échangent également avec le disque via des TFileStream sauf qu'avec SaveToFile c'est la totalité de la StringList qui part sur le disque alors qu'avec un write dans FileStream on ajoute y ajoute un pavé après l'autre.

    Au fait j'avais oublié tout à l'heure l'idée du FileStream était venue au début dans l'objectif de ne mettre qu'un minimum en mémoire. Mais puisque tu as choisi d'accumuler en mémoire la maximum avant d'envoyer l'accumulation sur le disque tu peux aussi cogiter sur la possibilité d'accumuler les combinaisons au fur et à mesure dans des MemoryStream puis d'envoyer les MemoryStream sur le disque via un FileStream (Stream2.CopyFrom(Stream1, Stream1.Size) )
    A+

  15. #35
    Membre actif Avatar de lun4t1k
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    276
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 276
    Points : 274
    Points
    274
    Par défaut
    Toujours des réponses complètes qui apportent beaucoup: merci.

    Citation Envoyé par Gilbert Geyer
    Re-bonjour,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    lun4t1k a écrit : Ne sachant pas combiens de combinaisons iront dans l'association t[name], je ne peux pas fixer de taille.
    ... je suppose que dans "t[name] := t[name] + #13#10 + Chaine" c'est "Chaine" qui représente une combinaison, donc ne pas confondre le nombre de combinaisons présentes dans "t[index]" avec indexMax qui est la taille du tableau "t". On parle de la même chose ?
    Oui. Chaine est la combinaison au format string. Au final t[i] contient une gros se chaine de caracteres contenant toutes les combis a placer dans le fichier i.
    En revanche, un interet du tableau associatif est de ne pas fixer de taille et de le faire fonctionner a la manière d'un hash. Faire grandir indexMax ne me semble pas utile : cela est fait automatiquement par le tableau associtid a chaque insertion d'une <clé, valeur>. (non?)

    Citation Envoyé par Gilbert Geyer
    ... ne pourrais tu pas faire par exemple un SetLength(t,1000) en tant qu'allocation prévisionnelle de départ et surveiller un compteur pour augmenter au moment opportun la taille avec SetLength(t,2000) ... et ainsi de suite avec un pas de 1000 comme dans cet exemple ou avec un pas d'augmentation différent ???
    On est bien d'accord que tu veux faire un setLength pour modifier indexMax?
    Si oui voir au dessus .

    Citation Envoyé par Gilbert Geyer
    Avec une StringList à la place du tableau, (si le principe d'une StringList était compatible avec tes besoins) ce serait plus simple car tant qu'il y a de la mém-vive-dispo on peut faire maStringList.Add(maChaine), pas besoin du SetLength dans ce cas , suffit de mettre maStringList.Add(maChaine) après un "try".
    Comme tu le dit en dessous, si je sature la memvive, le resultat sera la meme avec une stringlist.

    Citation Envoyé par Gilbert Geyer
    ... c'est certainement dû au fait que tu as passé le cap de la mem-vive-saturée et que Windows en arrière plan envoie l'excédent en mémoire moins vive basée sur des échanges avec le disque.

    ... c'est l'avantage du Stream et des StringList qui elles échangent également avec le disque via des TFileStream sauf qu'avec SaveToFile c'est la totalité de la StringList qui part sur le disque alors qu'avec un write dans FileStream on ajoute y ajoute un pavé après l'autre.
    Avec le disque?? alors passons!
    La string list enregistre tout d'un coup c'est bien, mais ce n'est pas l'ecriture sur fichier qui est longue :'(.

    Citation Envoyé par Gilbert Geyer
    Au fait j'avais oublié tout à l'heure l'idée du FileStream était venue au début dans l'objectif de ne mettre qu'un minimum en mémoire. Mais puisque tu as choisi d'accumuler en mémoire la maximum avant d'envoyer l'accumulation sur le disque tu peux aussi cogiter sur la possibilité d'accumuler les combinaisons au fur et à mesure dans des MemoryStream puis d'envoyer les MemoryStream sur le disque via un FileStream (Stream2.CopyFrom(Stream1, Stream1.Size) )
    A+
    Au debut tu disais je cite:
    Citation Envoyé par Gilbert Geyer
    ... le choix risque d'être vite fait :
    - TFileStream : y'a presque rien en mémoire,
    - TMemoryStream : t'as absolument tout dans la Memory,
    ... donc si ta mem-vive-dispo te permet d'y mettre tes 800Mo le TMemoryStream est jouable sinon Exit le TMemoryStream.
    Ca ira alors plus vite avec le memory car stocké dans la memvive et la limite de saturation imposé par windows serait alors plus grande?
    Sur le procédé, ca rajoute une étape, efficacité réelle?
    Je n'ai jamais testé, donc si vous avez du vécu


    Merci a tous!

  16. #36
    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
    Re-bonjour,

    En revanche, un interet du tableau associatif est de ne pas fixer de taille et de le faire fonctionner a la manière d'un hash. Faire grandir indexMax ne me semble pas utile : cela est fait automatiquement par le tableau associtid a chaque insertion d'une <clé, valeur>. (non?)
    ... je n'ai jamais utilisé de tableau associatif donc je pensais qu'il s'apparentait à un tableau avec les avantages/inconvénients des tableaux.
    ... par contre si ton tableau-assoc est basé sur le modèle du 05_tableaux_associatifs.zip qui utilise la classe TList cela se fait effectivement à chaque appel de la procedure TableauAssociatif.AjoutElement().
    ... donc "Exit les SetLength".

    Comme tu le dit en dessous, si je sature la memvive, le resultat sera la meme avec une stringlist.
    ... et le résultat sera le même avec n'importe quelle structure d'accumulation en mémoire.

    Avec le disque?? alors passons!
    ... j'ai pas bien pigé à quel aspect précisément cette remarque s'applique ? L'aspect "cap de la mem-vive-saturée" ? Ou celui relatif à "l'avantage du Stream et des StringList" ? J'ai peut être mal formulé ces passages.

    Ca ira alors plus vite avec le memory car stocké dans la memvive et la limite de saturation imposé par windows serait alors plus grande?
    Sur le procédé, ca rajoute une étape, efficacité réelle?
    ... il est évident que la limite de saturation de la mem-vive ne peut être agrandie qu'en ajoutant des barettes.
    ... "Sur le procédé, ca rajoute une étape, efficacité réelle?" : comme t'es en phase d'optimisation je dirais plutôt que ça remplacerait le tableau associatif et ses étapes par d'autres. Et pour ce qui est de l'efficacité réelle il n'y a qu'en comparant réellement deux solutions utilisées avec un même protocole d'essais que l'on peut se prononcer raisonnablement.
    Les TMemoryStreams n'étaient ré-évoqués qu'en tant qu'altarnative à ta récente question "Auriez vous une proposition? <String, TStringList> serait il mieux?".

    P.S du 15/07 - 11h56 :
    Suggestion pour éviter le désagrément du ralentissement dû au franchissement de la limite mem-vive-physique/entrée-en-action-de-la-mem-virtuelle entre en action : Surveiller la progression de la mem-vive-physique-disponible pour la soulager au bon moment par exemple selon le scénario suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
              While mem-vive-physique-disponible > length(maDernièreCombi) do
              begin .....
                      Code de chargement en mémoire
                      .....
              end;
              //Ici mem-vive-physique-disponible <= length(maDernièreCombi)
              Code (ou renvoi vers le Code) de copie des combis du tableau-associatif vers le disque
              Code (ou renvoi vers le Code) de libération de la mem-vive-physique occupée par le tableau-associatif
              Code éventuel (ou renvoi vers ce Code) de ré-initialisations pour recharger le tableau et la mémoire avec la fournée suivante de combis.
    ... et pour connaître la mem-vive-physique-dispo :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    function MemViveDispoOctets : integer;
    Var      Memory : TMemoryStatus; 
    begin    Memory.dwLength := SizeOf(Memory); 
             GlobalMemoryStatus(Memory); 
             Result := Memory.dwAvailPhys; 
    end;
    ... et pour la libération de la mem-vive-physique occupée par le tableau-associatif tu peux inclure dans une boucle la procedure TableauAssociatif.RetirerElement() dans laquelle Dispose(Elem) libère la mémoire allouée à chaque élément correspondant.
    A+

Discussions similaires

  1. Script pour manipuler une chaine d'un nom de fichier
    Par mond14 dans le forum Shell et commandes GNU
    Réponses: 6
    Dernier message: 23/05/2013, 20h37
  2. Manipulation d'une liste chainée en C++
    Par id_rima dans le forum C++
    Réponses: 11
    Dernier message: 21/06/2010, 10h50
  3. manipulation d'une liste chainé
    Par sorari dans le forum C++
    Réponses: 1
    Dernier message: 16/03/2005, 12h32

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