Se connecter avec
S'enregistrer | Connectez-vous

[Delphi] Concaténation de chaines et performances... {long}

Dernière réponse : dans Programmation

Je rencontre actuellement dans un des progs que je fais des pbs de performances...

Avec un coup de profiler, j'ai vu que ce qui prenait du temps etait une fonction (faite maison) bien particuliere dans laquelle je dois concaténer tout un tas de chaines et renvoyer le resultat (plusieurs dizaine de Ko) a la fonction appelante...

la boucle principale de la fonction consiste a ajouter au result la valeur de differentes variables plus un saut de ligne (CRLF)...

Bien evidemment, le code est un peu plus complexe, mais en simplifiant a l'extreme, ca donne qqchose comme ca:
  1. for i:= 0 to count-1 do
  2. result := result + #13#10 + chaine[i] ;


j'en ai déduit (peut-etre a tort) que ce qui prenait du temps etait la reservation/assignement de la memoire pour les chaines temporaires...


j'ai donc essayé de voir dans un prog. a part les alternatives possibles:
  • utilisation de l'operateur +

    en une fois: (nom de code: concat)
    1. for i:= 0 to count-1 do
    2. result := result + #13#10 + chaine[i] ;


    en 2 fois (nom de code: concat2)
    1. for i:= 0 to count-1 do
    2. begin
    3. result := result + #13#10;
    4. result := result + chaine[i];
    5. end;



  • utilisation de la fonction format (nom de code: format)
    1. for i:= 0 to count-1 do
    2. result := format('%s'#13#10'%s', [result,chaine[i]]);


  • assignement de la memoire par bloc de 8k et copie des chaines caracteres par caracteres (nom de code: array)
    1. aryPos := 0;
    2. setlength(aryResult,8000);
    3. FillChar(aryResult[aryPos], 8000, #0);
    4. for i:= 0 to count-1 do
    5. begin
    6. sItem := chaine[i];
    7. for aryIndex := 1 to length(sItem) do
    8. begin
    9. aryResult[aryPos] := sItem[aryIndex];
    10. inc(aryPos);
    11. end;
    12. end;


  • assignement de la memoire par bloc de 8k et copie des chaines via system.move() (nom de code: move)

    1. aryPos := 0;
    2. setlength(aryResult,8000);
    3. FillChar(aryResult[aryPos], 8000, #0);
    4. for i:= 0 to count-1 do
    5. begin
    6. sItem := chaine[i];
    7. System.Move(sItem[1], aryResult[aryPos],length(sItem));
    8. aryPos := aryPos + length(sItem);
    9. end;


    j'ai donc fait un petit prog pour tester cela et j'ai mesuré le temps pris pour chaques options...
    Le source est dispo ici



    voila les resultats que j'obtiens sur un PIV 2.4Ghz, les resultats sont en millisecondes :

    1. -------------------------------------------------------------
    2. Test avec 1000 boucles
    3. -------------------------------------------------------------
    4. concat : 31
    5. concat2: 0
    6. format : 47
    7. array : 0
    8. move : 0
    9.  
    10. -------------------------------------------------------------
    11. Test avec 5000 boucles
    12. -------------------------------------------------------------
    13. concat : 672
    14. concat2: 0
    15. format : 1609
    16. array : 0
    17. move : 0
    18.  
    19. -------------------------------------------------------------
    20. Test avec 10000 boucles
    21. -------------------------------------------------------------
    22. concat : 2766
    23. concat2: 0
    24. format : 6765
    25. array : 0
    26. move : 16


    il est clair que le format n'est pas la solution (on s'en doutait un peu des le debut). on le vire des tests suivant...
    le array et le move sont rapides, ca ne m'etonne pas...
    par contre je ne comprends pas les differences entre le concat et concat2 :??: 




    1. -------------------------------------------------------------
    2. Test avec 25000 boucles
    3. -------------------------------------------------------------
    4. concat : 19297
    5. concat2: 16
    6. format : ca va ramer... on passe ce test...!
    7. array : 0
    8. move : 94

    concat est au tas (on le vire des prochains tests), move commence a ralentir
    array semble un poil plus performant que concat2



    1. -------------------------------------------------------------
    2. Test avec 50000 boucles
    3. -------------------------------------------------------------
    4. concat : ca va ramer... on passe ce test...!
    5. concat2: 31
    6. format : ca va ramer... on passe ce test...!
    7. array : 16
    8. move : 297
    9.  
    10. -------------------------------------------------------------
    11. Test avec 75000 boucles
    12. -------------------------------------------------------------
    13. concat : ca va ramer... on passe ce test...!
    14. concat2: 47
    15. format : ca va ramer... on passe ce test...!
    16. array : 31
    17. move : 515
    18.  
    19. -------------------------------------------------------------
    20. Test avec 100000 boucles
    21. -------------------------------------------------------------
    22. concat : ca va ramer... on passe ce test...!
    23. concat2: 63
    24. format : ca va ramer... on passe ce test...!
    25. array : 46
    26. move : 1016
    27.  
    28. -------------------------------------------------------------
    29. Test avec 500000 boucles
    30. -------------------------------------------------------------
    31. concat : ca va ramer... on passe ce test...!
    32. concat2: 312
    33. format: ca va ramer... on passe ce test...!
    34. array : 282
    35. move : 24328

    move est au tas, array est toujours plus performant que concat2



    donc au final, on obtiens un classement avec
    1. array (copie car. par car.)
    2. concat2 (operateur +, une ligne par variable a concatener)
    3. move (copie direct en memoire)
    4. concat (operateur +, tout sur une ligne)
    5. format

    il y a plusieurs choses que je ne comprends pas dans ses resultats (si cette tendance est confirmée par d'autres):
    - pourquoi concat rame par rapport a concat2 ? ca ne devrait etre pas la meme chose au final pour le compilateur ?
    - pourquoi array est plus performant que move ? je pensais que ca aurait donné les memes resultats ou que move aurait eté plus rapide ?

    si qq'un a des des reponses a me donner , je suis preneur !
    merci :jap: 

    JY.
    Lassé par la pub ? Créez un compte

    Pour comparer avec un 2500+ Barton
    Compilé avec Delphi 5 , tu es en 6 je crois.
    -------------------------------------------------------------
    Test avec 25000 boucles
    -------------------------------------------------------------
    concat : 19385
    concat2: 10
    format : ca va ramer... on passe ce test...!
    array : 10
    move : 60

    -------------------------------------------------------------
    Test avec 50000 boucles
    -------------------------------------------------------------
    concat : ca va ramer... on passe ce test...!
    concat2: 20
    format : ca va ramer... on passe ce test...!
    array : 20
    move : 245

    Demain si je trouve un moment(au boulot ;)  ) je compile Avec D6 au boulot et j'essaie de comprendre.
    Lassé par la pub ? Créez un compte