Bonjour,
j'ai installé ce matin une version Trial XE5 puisque mon établissement scolaire propose de m'offrir une Architect Education... et comme je consacre toujours quelques jours pendant mes vacances à faire des comparatifs, je suis parti d'un petit projet Lazarus qui a pour objet de charger 10 000 enregistrements dans une table SQLite mémoire puis de les afficher dans une dbGrid ou dGrid (pour FMX). La table contient 3 champs : un integer, un varchar(20), un blob pour y placer une vignette.png 16*16.
En plus de Lazarus, j'ai réalisé le projet
- en VCL avec FireDac, FDquery et DataSource sur une dbGrid histoire de me remémorer l'interface de l'IDE
- en FMX avec cible Windows 32 également avec FireDac, FDquery, BindSourceDB et Grid.
- et en WinDev 18 sur cibles Windows 32 et 64 bits
Je pense que j'ai perdu la main en Delphi. Le projet pour charger les 10000 lignes met plus de 15 secondes dans les 2 cas et 1 seconde en Lazarus (et 5 à 7 secondes en WinDev suivant les essais exe32 sur 32 bits, exe32 sur 64 bits ou exe64 sur 64 bits)... évidemment sur la même machine.
En Delphi, le problème de la lenteur vient de ma manière de charger les vignettes dans le MemoryStream.... Si je charge une fois le MemoryStream, puis les 10 000 enregistrements donc les 10 000 Blobs avec celui-ci, le temps de remplissage descend à 2 secondes donc à peu près identique à celui de Lazarus (sauf qu'en Lazarus pour le même temps je vide et remplis mon Stream 10 000 fois).
En Lazarus
En FMX, le code est quasiment identique et visiblement mal optimisé
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 procedure TForm1.Button1Click(Sender: TObject); //imgSrc : TImage var sREQcreate, strDiff : String; startTime, endTime : Tdatetime; streamTMP : TMemoryStream; iLoc : Integer; bOK : Boolean; begin bOK := True; startTime := getTickCount; with SQLite3Connection1 do if not connected then connected := True; sREQcreate := 'CREATE TABLE test2013 ( teid INTEGER PRIMARY KEY, tenom VARCHAR(20), teimage BLOB);'; with SQLQuery1 do try SQL.Text := sREQcreate; ExecSQL; Close; except Close; bOK := False; Showmessage('Oups 1'); end; if bOK then try streamTMP := TMemoryStream.Create; for iLoc := 1 to 10000 do with SQLQuery1 do begin streamTMP.Size := 0; imgSrc.Picture.SaveToStream(streamTMP); with SQL, Params do begin Clear; SQL.Text := 'INSERT INTO test2013 '+ '(teid, tenom, teimage) '+ 'VALUES ' + '(:paID, :paNOM, :paIMAGE);'; ParamByName('paID').AsInteger := iLoc; ParamByName('paNOM').AsString := 'TEST'+ IntToStr(iLoc); ParamByName('paIMAGE').LoadFromStream(streamTMP, ftBlob); end; try ExecSQL; Close; except Close; bOK := False; break; end; end; endTime := getTickCount - startTime; strDiff := FloatToStr(endTime/1000); if bOK then showmessage(strDiff) else Showmessage('Oups 2'); finally streamTMP.Free; end; end;Enfin là n'est pas le problème pour l'instant.... mais va le devenir rapidement .
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 procedure TForm1.Button1Click(Sender: TObject); // imgSrc: TImage; var sREQcreate : String; streamTMP : TMemoryStream; iLoc : integer; StopWatch: TStopWatch; bOK : Boolean; begin bOK := True; StopWatch := TStopWatch.Create; StopWatch.Start; with FDconnection1 do if not connected then connected := True; sREQcreate := 'CREATE TABLE test2013 (teid INTEGER PRIMARY KEY, tenom VARCHAR(20), teimage BLOB);'; with FDQuery1 do try SQL.Text := sREQcreate; ExecSQL; Close; except Close; bOK := False; Showmessage('Oups 1'); end; if bOK then try streamTMP := TMemoryStream.Create; for iLoc := 1 to 10000 do begin streamTMP.Size := 0; imgSrc.Bitmap.SaveToStream(streamTMP); with FDQuery1 do begin with SQL, Params do begin Clear; SQL.Text := 'INSERT INTO test2013 '+ '(teid, tenom, teimage) '+ 'VALUES ' + '(:paID, :paNOM, :paIMAGE);'; ParamByName('paID').AsInteger := iLoc; ParamByName('paNOM').AsString := 'TEST'+ IntToStr(iLoc); ParamByName('paIMAGE').LoadFromStream(streamTMP, ftBlob); end; try ExecSQL; Close; except Close; bOK := False; break; end; end; end; stopWatch.Stop; if bOK then showmessage(FloatToStr(stopWatch.ElapsedMilliseconds/1000)) else Showmessage('Oups 2'); finally streamTMP.Free; end; end;
J'ai un problème en FMX (et son LiveBindings) que je ne rencontre pas en VCL (avec son DataSource). On peut le constater sur l'image ci-dessous. Je charge les 10000 enregistrements dans la table. Le LiveBindings n'en affiche que 200. Si je clique sur la 200ème ligne, on passe instantanément à 300. Si je reclique sur la 300ème ligne, il ne se passe rien. (ie on reste à 300)... Et si avec le DbNavigateur je clique sur le bouton [>>], j'arrive bien sur la ligne 10000. Mais la remontée vers la ligne 1 est tout aussi impossible : une tranche de 100 à 200, puis plus rien. J'ai regardé dans les "réglages"... sans succès. J'ai regardé sur Internet, pas mieux. Donc help ! où est le problème ?
Si quelqu'un a l'occasion de se pencher sur mon code... Voici le projet complet FMX. Il est forcément bancal quelque part au niveau "LiveBindings" mais je manque de Doc. Pas vu sur Internet non plus, il y a un (le) livre à acheter sur FMX ? Je sais... Il y a des vidéos... Mais je n'apprends pas correctement avec ce support.... J'ai besoin d'un livre qui "va à ma vitesse", que je peux annoter...
D'avance merci.
Cordialement. Gilles
PS :
- Même exercice demain entre C++Builder FMX et C++/Qt... Il vaut mieux débrancher... entre Pascal et C++.
- Ci-joint l'exécutable Laz32 du même projet [source dispo sur le forum lazarus] qui met en évidence -c'est le moins qu'on puisse dire- la différence de vitesse d'exécution des 2 codes.
Partager