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 :

Chargement de données dans un thread


Sujet :

Langage Delphi

  1. #1
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 214
    Points : 223
    Points
    223
    Par défaut Chargement de données dans un thread
    Bonjour,

    J'utilise Delphi 10.4.2 avec une application FMX.
    Je dois charger un fichier texte contenant une liste de mot.
    Tout fonctionnait bien jusqu'à ce que l'idée folle me passe par la tête d'utiliser un thread pour charger ces données car le traitement peut être très long.

    Je me suis inspiré de cette page, mais je dois faire n'importe quoi , car cela ne fonctionne pas.

    J'ai des erreurs mémoires lors du traitement du fichier.

    Voici les composants

    Nom : 1.png
Affichages : 697
Taille : 9,1 Ko

    Voici les liaisons

    Nom : 2.png
Affichages : 672
Taille : 6,3 Ko

    et mon code

    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
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    unit fMain;
     
    interface
     
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes,
      System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
      FMX.Controls.Presentation, FMX.StdCtrls, FMX.Layouts, FMX.ListBox,
      FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param,
      FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf,
      System.Rtti, System.Bindings.Outputs, FMX.Bind.Editors, Data.Bind.EngExt,
      FMX.Bind.DBEngExt, Data.Bind.Components, Data.Bind.DBScope, Data.DB,
      FireDAC.Comp.DataSet, FireDAC.Comp.Client, FireDAC.Stan.StorageBin,
      System.Threading;
     
    type
      TForm2 = class(TForm)
        ListBox1: TListBox;
        btnLoad: TButton;
        od1: TOpenDialog;
        ProgressBar1: TProgressBar;
        FDMemTable1: TFDMemTable;
        FDStanStorageBinLink1: TFDStanStorageBinLink;
        DataSource1: TDataSource;
        FDMemTable1word: TStringField;
        BindSourceDB1: TBindSourceDB;
        BindingsList1: TBindingsList;
        LinkListControlToField1: TLinkListControlToField;
        procedure FormDestroy(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure btnLoadClick(Sender: TObject);
      private
        FLst: TArray<string>;
        FTask: ITask;
        procedure LoadFile;
        procedure EndTask;
        procedure AddWord(const word: string);
        procedure ProgressValue(val: Integer);
      public
      end;
     
    var
      Form2: TForm2;
     
    implementation
     
    {$R *.fmx}
     
    uses
      System.IOUtils;
     
    procedure TForm2.FormCreate(Sender: TObject);
    begin
      if (FDMemTable1.Active) then
        FDMemTable1.Close;
      FDMemTable1.ResourceOptions.Persistent := True;
      FDMemTable1.ResourceOptions.PersistentFileName :=
        TPath.Combine(TPath.GetDocumentsPath, 'MyDatas.bin');
      FDMemTable1.Open;
    end;
     
    procedure TForm2.FormDestroy(Sender: TObject);
    begin
      FDMemTable1.Close;
    end;
     
    procedure TForm2.btnLoadClick(Sender: TObject);
    var
      task: ITask;
    begin
      btnLoad.Enabled := False;
     
      if (od1.Execute) then
      begin
        try
          FLst := TFile.ReadAllLines(od1.FileName);
          ListBox1.BeginUpdate;
          ProgressBar1.Value := 0;
          ProgressBar1.Max := Length(FLst);
     
          FTask := TTask.Create(LoadFile);
          FTask.Start;
        except
          on e: Exception do
            ShowMessage(e.Message);
        end;
      end;
    end;
     
    procedure TForm2.LoadFile;
    var
      i: Integer;
    begin
      try
        for i := 0 to Pred(Length(FLst)) do
        begin
          TThread.Queue(nil,
            procedure
            begin
              ProgressValue(i);
            end);
     
          if (FLst[i].Length >= 6) and (FLst[i].Length <= 12) then
          begin
            TThread.Queue(nil,
              procedure
              begin
                AddWord(FLst[i]);
              end);
          end;
        end;
      finally
        TThread.Queue(nil, EndTask);
      end;
    end;
     
    procedure TForm2.ProgressValue(val: Integer);
    begin
      ProgressBar1.Value := val;
    end;
     
    procedure TForm2.AddWord(const word: string);
    begin
      FDMemTable1.Append;
      FDMemTable1.FieldByName('word').AsString := word;
      FDMemTable1.Post;
    end;
     
    procedure TForm2.EndTask;
    begin
      FTask := nil;
      ListBox1.EndUpdate;
      ShowMessage('Done');
      btnLoad.Enabled := True;
    end;
     
    end.
    Merci d'avance pour vos conseils.

  2. #2
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    tu fais un gros mélange entre main thread et thread secondaire...ça n'a pas bcp d'intérêt et ça provoque des erreurs

    manifestement tu veux alimenter une BDD à partir d'un fichier texte

    1) tu crées un procédure qui le fait sans passer par un thread et qui est autonome, donc pas de référence à la fiche, tu crées ton FDMenTable, tu charges ton fichier, tu aliments la table et tu supprimes tout

    une fois que a fonctionne

    2) tu appelles cette procédure depuis un Thread

    si tu tiens à avoir une progression, tu utilises un Message non bloquant...bon je sais plus si on peut faire sans un FMX, sous Windows j'utilise PostMessage() l'intérêt c'est que ça ne ralenti pas le Thread et que le thread principal traite le message quand il en a le temps

    sous FMX faut utiliser ça il me semble
    https://docwiki.embarcadero.com/Libr...er.SendMessage

  3. #3
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 764
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 764
    Points : 13 386
    Points
    13 386
    Par défaut
    Mis à part les conseils avisés de Paul, ce code ne fonctionnerait pas comme attendu et l'erreur mémoire pourrait provenir de la capture de la variable i.

    Lorsque tu écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    TThread.Queue(nil,
      procedure
      begin
        AddWord(FLst[i]);
      end);
    la variable i, locale à la procédure LoadFile, est capturée afin d'en étendre la durée de vie. Il est en effet possible que cette procédure dans un thread de travail finisse avant que la tâche principale ait traité la file. i ne doit donc pas être libérée à la sortie de LoadFile.

    Mais c'est la variable qui est capturée et non son contenu. Lorsqu'AddWord est finalement exécuté et si la boucle n'est pas terminée AddWord utilisera la valeur actuelle et non celle au moment de la capture. Les choses se corsent encore si la boucle est terminée puisqu'une variable de boucle n'est valide que dans la boucle proprement dite. Au moment du traitement par AddWord, i est dans les choux !

    Pour illustrer cela, voici un exemple censé envoyé les nombres 1 à 20 dans une ListBox :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      TTask.Run(procedure
                begin
                  for var i := 1 to 20 do
                    TThread.Queue(nil, procedure
                                       begin
                                         ListBox1.AddItem(i.ToString, nil);
                                       end);
                end);
    end;
    Avec un peu de chance, il y aura 2-3 valeurs dans la fourchette mais la plupart dépassent 20. Dans ton cas, tu es hors tableau FLst d'où peut-être les problèmes d'accès mémoire


    Dans l'exemple ci-dessus, remplacer Queue par Synchronize corrigerait le problème puisque la variable capturée serait immédiatement utilisée mais pour Queue il faut s'assurer qu'une variable immuable est utilisée. On pourrait par exemple le faire ainsi :
    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
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      var DoQueue := procedure(const Value :string)
                     begin
                       // Value est capturé et ne changera plus
                       TThread.Queue(nil, procedure
                                          begin
                                            ListBox1.AddItem(Value, nil);
                                          end);
                     end;
     
      TTask.Run(procedure
                begin
                  for var i := 1 to 20 do
                    DoQueue(i.ToString);
                end);
    end;
    TThread.Queue est légèrement plus compliquée à utiliser que TThread.Synchronize s'il y a capture de variables. On ne passe pas du second au premier sans un minimum de réflexion

  4. #4
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 214
    Points : 223
    Points
    223
    Par défaut
    Merci de vos réponses.
    Effectivement, je connais mal le fonctionnement des threads. Je n'avais tester que des petits exemples jusqu'à maintenant.
    Je savais bien que ce que je faisais n'étais pas correcte.

    Andnotor, je commence effectivement à comprendre ce qui ne va pas dans mon code.
    Je n'ai pas du tout comprendre encore car si mon fichier est maintenant bien intégré, il reste quelques anomalies.
    Ma fenêtre se bloque lors de l'intagrétion du fichier et la progressbar ne s'actualise pas.

    Voici mon code modifié.

    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
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    unit fMain;
     
    interface
     
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes,
      System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
      FMX.Controls.Presentation, FMX.StdCtrls, FMX.Layouts, FMX.ListBox,
      FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param,
      FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf,
      System.Rtti, System.Bindings.Outputs, FMX.Bind.Editors, Data.Bind.EngExt,
      FMX.Bind.DBEngExt, Data.Bind.Components, Data.Bind.DBScope, Data.DB,
      FireDAC.Comp.DataSet, FireDAC.Comp.Client, FireDAC.Stan.StorageBin,
      System.Threading;
     
    type
      TForm2 = class(TForm)
        ListBox1: TListBox;
        btnLoad: TButton;
        od1: TOpenDialog;
        ProgressBar1: TProgressBar;
        FDMemTable1: TFDMemTable;
        FDStanStorageBinLink1: TFDStanStorageBinLink;
        DataSource1: TDataSource;
        FDMemTable1word: TStringField;
        BindSourceDB1: TBindSourceDB;
        BindingsList1: TBindingsList;
        LinkListControlToField1: TLinkListControlToField;
        procedure FormDestroy(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure btnLoadClick(Sender: TObject);
      private
        FLst: TArray<string>;
        FTask: ITask;
        procedure LoadFile;
        procedure EndTask;
        procedure ProgressValue(const val: Integer; const word: string);
      public
      end;
     
    var
      Form2: TForm2;
     
    implementation
     
    {$R *.fmx}
     
    uses
      System.IOUtils;
     
    procedure TForm2.FormCreate(Sender: TObject);
    begin
      if (FDMemTable1.Active) then
        FDMemTable1.Close;
      FDMemTable1.ResourceOptions.Persistent := True;
      FDMemTable1.ResourceOptions.PersistentFileName :=
        TPath.Combine(TPath.GetDocumentsPath, 'MyDatas.bin');
      FDMemTable1.Open;
    end;
     
    procedure TForm2.FormDestroy(Sender: TObject);
    begin
      FDMemTable1.Close;
    end;
     
    procedure TForm2.btnLoadClick(Sender: TObject);
    var
      task: ITask;
    begin
      btnLoad.Enabled := False;
     
      if (od1.Execute) then
      begin
        try
          FLst := TFile.ReadAllLines(od1.FileName);
          ListBox1.BeginUpdate;
          ProgressBar1.Value := 0;
          ProgressBar1.Max := Length(FLst);
     
          TTask.Run(LoadFile);
        except
          on e: Exception do
            ShowMessage(e.Message);
        end;
      end;
    end;
     
    procedure TForm2.LoadFile;
    begin
      try
        for var i := 0 to Pred(Length(FLst)) do
        begin
          if (FLst[i].Length >= 6) and (FLst[i].Length <= 12) then
            ProgressValue(i, '')
          else
            ProgressValue(i, FLst[i]);
        end;
      finally
        EndTask;
      end;
    end;
     
    procedure TForm2.ProgressValue(const val: Integer; const word: string);
    begin
      TThread.Queue(nil,
        procedure
        begin
          ProgressBar1.Value := val;
     
          if (not word.IsEmpty) then
          begin
            FDMemTable1.Append;
            FDMemTable1.FieldByName('word').AsString := word;
            FDMemTable1.Post;
          end;
        end);
    end;
     
    procedure TForm2.EndTask;
    begin
      TThread.Queue(nil,
        procedure
        begin
          FTask := nil;
          ListBox1.EndUpdate;
          ShowMessage('Done');
          btnLoad.Enabled := True;
        end);
    end;
     
    end.
    Merci de votre patience et votre aide.

  5. #5
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 119
    Points : 41 254
    Points
    41 254
    Billets dans le blog
    63
    Par défaut
    Bonjour,

    Il y a déjà un bon moment je pointais les vidéos, hyper pédagogues, d'Olaf Monien pour tout ce qui est thread, il est peut-être temps pour moi de remettre, a minima, un lien (parmi d'autres à googliser avec les mots "olaf+monien+thread ).

    dernièrement encore (appli FMX bien sûr) j'ai écrit ceci pour une récupération de données particulièrement longue

    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
    procedure TFormPrestaStocks.FormCreate(Sender: TObject);
    begin
     AniIndicator1.Enabled:=True;
     TTask.run(GetDatas);
    end;
     
    procedure TFormPrestaStocks.GetDatas;
    begin
     with Datas do
      begin
        FDStocksDispo.Open();  // requête longue 
        MemStocks.CloneCursor(FDStocksDispo);  // mise en fdmemtable
        FDStocksDispo.Close;
     
        TThread.Synchronize(nil,
                  procedure
                  begin
                    // FillGrille;
                    AniIndicator1.Enabled:=False;
                    TabControl1.Next();
                  end);
        end; 
    end;
    autre chose, si j'ai bien lu, en diagonale car dimanche matin, tu charges un fichier texte et ça à l'idse d'un boucle et des append
    as-tu pensé a un bon petit fdbatchmove ? cela devrait être dans l'ordre du possible malgré un traitement que je n'ai pas trop saisi if (FLst[i].Length >= 6) and (FLst[i].Length <= 12) then. Bien que cette approche me titille, je ne peux malheureusement pas faire d'essais, ce matin je dois me mettre au piano (de cuisine) pour concocter un repas d'anniversaire

  6. #6
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 214
    Points : 223
    Points
    223
    Par défaut
    Je te remercie pour ces pistes, je vais voir ces liens.

    Juste pour expliquer, je cherche à faire un pendu en m'inspirant de
    .
    J'ai donc une liste de mot que j'utilise pour sélectionner de mot à trouver.

    Sinon, je ne connais pas encore bien firedac.
    A vrai dire je travail sur Delphi 7 et je me forme sur mon temps perso sur Delphi 10.
    Je découvre donc Firedac et FMX.

  7. #7
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 119
    Points : 41 254
    Points
    41 254
    Billets dans le blog
    63
    Par défaut
    Bon, je n'ai pas regardé les Bootscamps de Patrick difficiles à caser dans mon agenda.
    Pour ce qui est de FDBatchmove c'est hyper simple, j'ai rapidement fait un test, juste en design mode, sans intégrer de progressbar ni de contrôle de longueurs minimales (la maxi étant gérée automatiquement dans ce cas.
    Bien évidement, je n'ai pas de fichier texte précis, étant donné que c'était juste pour vérifier mon hypothèse.

    Tu as besoin de ça
    Nom : Capture.PNG
Affichages : 598
Taille : 30,1 Ko
    Ensuite, tu as juste à indiquer le fichier teste à traiter pour le fdBatchMoveTextReader. fdBatchMoveTextReader.filename:=
    Nom : Capture_1.PNG
Affichages : 587
Taille : 15,4 Ko
    si tu as au préalable défini le "champ" à récupérer (ici j'indique un string de longueur 18)
    Nom : Capture_3.PNG
Affichages : 593
Taille : 12,3 Ko
    tu peux déjà faire l'essai avec l'EDI (clic droit sur le composant fdbatchmove/exécuter) puis reagder ce qu'il y a dans la table (clic droit sur fdmemtable/modifier l'ensemble de données).

    Pour ce qui est du progressbar, tu as l'évènement OnProgress du FDBatchMove je ne maitrise pas les autres évènements.
    Mon avis, le OnWriteRecord pourrait correspondre pour gérer la limite de taille minimum (aaction:=paSkip) sauf que je n'ai aucune idée de la méthode pour obtenir la valeur de la colonne (si ce n'est dans onWriteValue . Je peux suggérer une approche en deux temps, après avoir rempli la table, supprimer les enregistrements ont la colonne mot est de taille inférieure au critère par SQL mais cela implique de rajouter l'utilisation de localSQL et là encore je me bats toujours un peu avec (donc à éviter )

    J'allais te demander un fichier mais j'ai trouvé un zip (en p.j.) sur ce site qui conviendra parfaitement.
    Cela me permettrait d'apprendre à gérer un zip avec la nouvelle version D11, de faire un test de chargement du zip directement sur le site (donc un pendu multilingue )
    Fichiers attachés Fichiers attachés

  8. #8
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 119
    Points : 41 254
    Points
    41 254
    Billets dans le blog
    63
    Par défaut
    Pour info, toujours en n'utilisant que l'EDI
    Nom : Capture.PNG
Affichages : 597
Taille : 24,1 Ko
    j'ai constaté que cela était tellement rapide que le thread (ou du moins la gauge) me semblait bien inutile.
    Maintenant, si un index est à construire ... un thread oui (comme j'ai l'ai proposé), une gauge non (AMHA la construction de l'index sera plus longue que le rapatriement des données)

  9. #9
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 214
    Points : 223
    Points
    223
    Par défaut
    Bonjour,

    Ton approche à l'air effectivement beaucoup plus efficace.
    Je vais regarder cela en détail, car je ne connais pas du tout ce type de fonctionnement.

    De mon côté, je m'étais contenté de reprendre le fonctionnement du tuto.
    Je vais tout de même continuer à explorer le fonctionnement via un thread pour essayer de comprendre comment cela fonctionne.

    Pour mes tests, j'étais parti sur cette liste (+330k mots).

  10. #10
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 119
    Points : 41 254
    Points
    41 254
    Billets dans le blog
    63
    Par défaut
    Citation Envoyé par oneDev Voir le message
    Pour mes tests, j'étais parti sur cette liste (+330k mots).
    Effectivement, il y en a beaucoup plus que mes 54k, je vais faire le test
    le test est presque tout aussi rapide (cela écrit il y a un bémol d'encodage)
    Nom : Capture.PNG
Affichages : 572
Taille : 4,8 Ko

    Edit :
    mon fichier : total mots tailles<12 22740 en 70 millisecondes + - 10
    le tien : total 336531 en 1058 millisecondes

    d'où mon scepticisme pour la gauge

  11. #11
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 119
    Points : 41 254
    Points
    41 254
    Billets dans le blog
    63
    Par défaut
    pour continuer, je confirme que faire un filtre sur la table en mémoire pour n'obtenir que les mots correspondants aux critères, ce que j'ai codé ainsi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Fdmemtabledico.filter:='mot<>''''';
    Fdmemtabledico.filtered:=true;
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure TDataModule2.FDBatchMove1WriteValue(ASender: TObject;
      AItem: TFDBatchMoveMappingItem; var AValue: Variant);
    begin
    if (Length(AValue)<4) OR (Length(AValue)>12) then
     AValue:=EmptyStr;
    end;
    est plus longue (16s) que la récupération des données (1s)
    Je n'ai pas réussi à traiter ça directement avec FDBatchMove

  12. #12
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 214
    Points : 223
    Points
    223
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    mon fichier : total mots tailles<12 22740 en 70 millisecondes + - 10
    le tien : total 336531 en 1058 millisecondes

    d'où mon scepticisme pour la gauge
    Effectivement dans ces conditions, pas besoin.
    Je vais tester cela dès que possible.

  13. #13
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 119
    Points : 41 254
    Points
    41 254
    Billets dans le blog
    63
    Par défaut
    Attention, il y a quand même pas mal de choses "piégeuses".
    Niveau fdmemtable pas évident cette histoire de nom de colonne j'ai dû m'y reprendre à plusieurs fois
    niveau reader, comme le fichier texte ne contient pas, en 1°ligne, de nom de colonne je n'ai pas pu utiliser* de mappings ( *ou plutôt toutes tentative de faire du) ce qui m'a peut être empêché d'utiliser le OnWriteRecord.

    La documentation est rare sur ces évènements et google n'est guère plus bavard

    [Edit]
    Effectivement, j'ai ajouté en première ligne du fichier "mot"
    indiqué que cette ligne était le nom de colonne
    Nom : Capture.PNG
Affichages : 576
Taille : 13,0 Ko

    et j'ai pu définir les mappings et écrire ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    procedure TDataModule2.FDBatchMove1WriteRecord(ASender: TObject;
      var AAction: TFDBatchMoveAction);
    var m : String;
    begin
    AAction:=TFDBatchMoveAction.paInsert;
    m:=FDBatchmove1.Mappings[0].ItemValue;
    accept:=(Length(m)>=4) AND (Length(m)<=12);
    if not Accept then AAction:=TFDBatchMoveAction.paSkip;
    end;
    ce qui enlève bien tout les mots ne rentrant pas dans les critères

    -Batchmove total 259131 en 1005 millisecondes

    Pas mal et donc pas de thread (déjà inclus dans batchmove) à faire

    reste l'encodage qui m'incommode, s'affichant pourtant correctement dans notepad
    si j'indique UTF8 j'ai un planton au bout de quelques (35000) mots
    si j'indique défaut, je n'ai pas certains mots écrits correctement (cf image écran plus haut)

  14. #14
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 214
    Points : 223
    Points
    223
    Par défaut
    Je viens de tester ta méthode avec les FDBatch, cela fonctionne effectivement très bien.
    J'ai également ce problème d'encodage, mais sinon, ça fonctionne très bien.
    J'ai contourné le problème en enregistrant la liste en ANSI et de cette manière les caractères accentués sont bien pris en compte.

    Je vais tout de même reprendre ma version avec un Thread simplement pour comprendre comment cela doit fonctionner.

  15. #15
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 119
    Points : 41 254
    Points
    41 254
    Billets dans le blog
    63
    Par défaut
    Citation Envoyé par oneDev Voir le message
    J'ai contourné le problème en enregistrant la liste en ANSI
    Effectivement c'était la seule solution que j'avais pu trouver pour ce problème d'encodage. J'ai tenté le FDBatchMoveTextReader1.Encoding:=TFDEncoding.ecutf8; mais le traitement s'est arrêté à byzantins (34k mots) je ne sais pourquoi, enfin si c'est certainement 'çà' qui ne lui plait pas

    J'ai quand même insisté (tout d'abord en ôtant le 'çà') ce qui m'a levé une erreur de conversion de variant sur l'instruction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     m:=FDBatchmove1.Mappings[0].ItemValue
    en modifiant l'évènement OnWriteRecord ainsi
    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
    procedure TDataModule2.FDBatchMove1WriteRecord(ASender: TObject;
      var AAction: TFDBatchMoveAction);
    var m : String;
    begin
    AAction:=TFDBatchMoveAction.paInsert;
    if VarIsNull(FDBatchmove1.Mappings[0].ItemValue)
      then m:=''
      else  m:=FDBatchmove1.Mappings[0].ItemValue;
    
    accept:=(Length(m)>=4) AND (Length(m)<=12);
    accept:=accept and (not m.Contains('-'));  // enlève les mots avec trait d'union 
    accept:=Accept AND (ord(m[1])>ord('Z'));  // enlève les noms propres (de ma liste plus courte) 
    if not Accept then AAction:=TFDBatchMoveAction.paSkip;
    end;
    J'ai enfin réussi à traiter le fichier UTF8 (cela dit après l'avoir sauvegardé avec notepad pour l'encodage, 'çà' ôté) en environ 1 seconde.

    code d'essai
    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
    procedure TForm1.Button1Click(Sender: TObject);
    var i : integer;
        watch : TStopWatch;
    begin
     watch:=TStopwatch.Create;
     watch.Start;
     with datamodule2 do
     begin
     //  FDMemTableDico.EmptyDataSet;  // inutile si options.ClearDest=true
      FDMemTableDico.Filtered:=false;
    //  FDBatchMoveTextReader1.FileName:='D:\serge\Documents\liste_francais\liste_francais.txt'; 
    //  FDBatchMoveTextReader1.FileName:='D:\serge\Documents\liste.de.mots.francais.frgut.txt'; // arrêt à byzantins
    //  FDBatchMoveTextReader1.FileName:='D:\serge\Documents\liste.de.mots.francais.ansi.txt'; // ansi via notepad
      FDBatchMoveTextReader1.FileName:='D:\serge\Documents\liste.de.mots.francais.utf8.txt'; // utf8 via notepad
      FDBatchMoveTextReader1.Encoding:=TFDEncoding.ecutf8;
      i:=FDBatchMove1.Execute;
      Showmessagefmt('Batchmove total  %d en %d millisecondes',[i,Watch.ElapsedMilliseconds]);
     end;
     watch.Stop;
    end;

    Juste une remarque pour le jeu du pendu, je trouve que cette liste est trop importante (à cause des conjugaisons et des pluriels) AMHA la liste que je proposai au début devrait largement suffire (filtrée comme dans le code)
    pour ce qui est d'un mot le plus long par contre ...

  16. #16
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 214
    Points : 223
    Points
    223
    Par défaut
    Merci je vais tester ça.

    On est bien d'accord que dans le cadre d'un jeu cela ne sert à rien.
    En fait, pour le moment, j'ai mis de côté le jeu pour me pencher sur ces problèmes de chargement de données. Je continue de tester avec des threads. Pour ces tests, ce fichiers est très bien.

  17. #17
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 764
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 764
    Points : 13 386
    Points
    13 386
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Niveau fdmemtable pas évident cette histoire de nom de colonne j'ai dû m'y reprendre à plusieurs fois
    niveau reader, comme le fichier texte ne contient pas, en 1°ligne, de nom de colonne je n'ai pas pu utiliser* de mappings ( *ou plutôt toutes tentative de faire du) ce qui m'a peut être empêché d'utiliser le OnWriteRecord.
    S'il n'y a pas d'entête tu dois tout faire manuellement : ajouter les colonnes à Reader.Fields, MemTable.FieldDefs et BatchMove.Mappings.
    S'il y en a, GuessFormat suffit "généralement" (ça va entre autre dépendre de la taille de l'échantillon (AnalyzeSample) et de sa qualité).

    Citation Envoyé par SergioMaster Voir le message
    reste l'encodage qui m'incommode, s'affichant pourtant correctement dans notepad
    si j'indique UTF8 j'ai un planton au bout de quelques (35000) mots
    si j'indique défaut, je n'ai pas certains mots écrits correctement (cf image écran plus haut)
    La subtilité est Reader.RecordFormat à mettre sur rfFieldPerLine. Le parser semble s'emmeller les pinceaux s'il n'y a qu'une seule colonne. Le fichier fournit par OneDev est alors correctement lu en utf8.

    Citation Envoyé par SergioMaster Voir le message
    ...mais cela implique de rajouter l'utilisation de localSQL et là encore je me bats toujours un peu avec (donc à éviter )
    Juste un petit rafraichissement pour ceux que ça intéresse (avec SQLite).

    Déposer :
    • un TFDPhysSQLiteDriverLink pour le driver SQLite ;
    • un TFDConnection avec DriverName = SQLite ;
    • un TFDLocalSQL connecté à notre composant ci-dessus ;
    • un TFDQuery (par exemple) connecté aussi à ce même composant avec sa propriété LocalSQL fixée sur le TFDLocalSQL.


    Puis ajouter la table (ici FDMemTableDico) à TFDLocalSQL.DataSets.

    On peut ensuite balancer toutes les requêtes voulues dans notre TFDQuery comme s'il était connecté à tout autre SGBD.
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT *
    FROM FDMemTableDico
    WHERE LENGTH(Mot) BETWEEN 4 AND 12

  18. #18
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 119
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 119
    Points : 41 254
    Points
    41 254
    Billets dans le blog
    63
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    La subtilité est Reader.RecordFormat à mettre sur rfFieldPerLine. Le parser semble s'emmeller les pinceaux s'il n'y a qu'une seule colonne.
    Effectivement, merci pour l'astuce
    Le parser semble s'emmeller les pinceaux s'il n'y a qu'une seule colonne.
    Il faudrait certainment le signaler sur le portail qualité si ce n'est déjà fait

  19. #19
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 764
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 764
    Points : 13 386
    Points
    13 386
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Il faudrait certainment le signaler sur le portail qualité si ce n'est déjà fait
    Si une propriété est là, à mon avis, ils ont cherché mais pas trouvé la parade pour automatiser

  20. #20
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 214
    Points : 223
    Points
    223
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    La subtilité est Reader.RecordFormat à mettre sur rfFieldPerLine. Le parser semble s'emmeller les pinceaux s'il n'y a qu'une seule colonne. Le fichier fournit par OneDev est alors correctement lu en utf8.
    Super, j'ai un peu galéré, mais j'ai finalement réussi à faire fonctionner ce code.
    Merci beaucoup de votre aide !

Discussions similaires

  1. [DOM] Chargement de données dans fichier XML ?
    Par titoc dans le forum Bibliothèques et frameworks
    Réponses: 4
    Dernier message: 01/06/2008, 12h31
  2. [MySQL] chargement des données dans un formulaire
    Par super-java dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 22/04/2008, 12h49
  3. Chargement de données dans un tableau Forms
    Par presser dans le forum Forms
    Réponses: 2
    Dernier message: 15/04/2008, 18h28
  4. Réponses: 2
    Dernier message: 29/03/2007, 09h50
  5. [C#] Utilisation des données dans un Thread
    Par Seth77 dans le forum C#
    Réponses: 12
    Dernier message: 24/10/2006, 14h14

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