Aie ! Lenteur boucle sur element de tableau VS variable VS blob

Bonjour,

je fais suite a des tests sur le fil https://forums.4d.com/Post/FR/27219206/1/27239080.

Je tombe un peu sur le C…L devant ces nouveaux tests … Dans une très grande boucle (350 millions …) j’utilise la commande LIRE MOTS CLE TEXTE * . L’opération me semblait un peu longue, donc j’ai refait des tests de vitesse, et patatra !

En millisecondes (compilé)

  • Elem. de tableau : 1602
  • Variable texte : 43 => 40 fois plus rapide que le tableau… Sic !
  • Variable blob : 110

concatener le texte découpé est 40 fois plus lent en tableau
boucle($i;1;23)
$TABL{elem}:=$TABL{elem}+$MOT{$i}
fin de boucle

que

$vartext:=""
boucle($i;1;23)
$vartext:=$vartext+$MOT{$i}
fin de boucle
$TABL{elem}:=$vartext

Il me semble que @Arnaud avait déjà plus ou moins fait ce genre de test il y a longtemps, mais je ne retrouve pas.

voici le code de test simple :

<code 4D>
C_TEXTE($champ)
C_BLOB($blob)
C_ENTIER LONG($i;$u;$a)

TABLEAU TEXTE($PRO_MOTSCLES;1)

$qT:=0
Si (Mode compilé)
$qt:=1000
Sinon
$qt:=1000
Fin de si

$txt:=“Bourg-en-Bresse 01 AVALANCHE nettoyage 01000 Réparation automobile de véhicules automobiles légers: entretien courant, Nettoyage courant des bâtiments, SARL unipersonnelle . Ain 01 5 Rue des CRETS”
$i:=1

$T1:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
Boucle ($a;1;Taille tableau($MOTS))
$PRO_MOTSCLES{$i}:=$PRO_MOTSCLES{$i}+$MOTS{$a}+" "
Fin de boucle
Fin de boucle
$T1:=Nombre de millisecondes-$T1

$T2:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
$champ:=""
Boucle ($a;1;Taille tableau($MOTS))
$champ:=$champ+$MOTS{$a}+" "
Fin de boucle
$PRO_MOTSCLES{$i}:=$champ
Fin de boucle
$T2:=Nombre de millisecondes-$T2

$T3:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;)
FIXER TAILLE BLOB($blob;0)
Boucle ($a;1;Taille tableau($MOTS))
TEXTE VERS BLOB($MOTS{$a}+" ";$blob;UTF8 texte sans longueur;
)
Fin de boucle
$PRO_MOTSCLES{$i}:=BLOB vers texte($blob;UTF8 texte sans longueur)

Fin de boucle
$T3:=Nombre de millisecondes-$T3

ALERTE("Elem. tablo : “+Chaîne($T1)+”\rVar locale : “+Chaîne($T2)+”\rBlob : "+Chaîne($T3))

</code 4D>

Aller chercher dans la mémoire un element de tableau semble etre un peu comme les pointeurs … ca coute très cher en temps… Si l’on réutilise un élément plusieurs fois, il vaut mieux le transcrire en variable locale puis réatribuer le résultat a l’élément de tableau a la fin (si ce n’est pas une concaténation de texte trop long sinon ça s’effondre vite).

Je vais devoir revoir pas mal de code … :-?

Je n’ai pas testé avec les tableaux objet, mais je suppose que c’est probablement la même chose …?

: Marc LONGO

Je n’ai pas testé avec les tableaux objet, mais je suppose que c’est
probablement la même chose …? réponse : non il n’y a pas d’écarts avec les objets;

En redémarrant ma machine j’obtiens des écarts moins importants mais conséquents:

En millisecondes (compilé)

  • Elem. de tableau : 890
  • Variable texte : 42 => 20 fois plus rapide que le tableau… Sic !
  • Variable blob : 101
  • Tableau Objet : 67
  • Variable Objet : 63

Code de test avec Objet:
<code 4D>
C_TEXTE($champ)
C_BLOB($blob)
C_ENTIER LONG($i;$u;$a)

TABLEAU TEXTE($PRO_MOTSCLES;100000)

$qT:=0
Si (Mode compilé)
$qt:=1000
Sinon
$qt:=1000
Fin de si

$txt:=“Bourg-en-Bresse 01 AVALANCHE nettoyage 01000 Réparation automobile de véhicules automobiles légers: entretien courant, Nettoyage courant des bâtiments, SARL unipersonnelle . Ain 01 5 Rue des CRETS”
$i:=1

$T1:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
Boucle ($a;1;Taille tableau($MOTS))
$PRO_MOTSCLES{$i}:=$PRO_MOTSCLES{$i}+$MOTS{$a}+" "
Fin de boucle
Fin de boucle
$T1:=Nombre de millisecondes-$T1

$T2:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
$champ:=""
Boucle ($a;1;Taille tableau($MOTS))
$champ:=$champ+$MOTS{$a}+" "
Fin de boucle
$PRO_MOTSCLES{$i}:=$champ
Fin de boucle
$T2:=Nombre de millisecondes-$T2

$T3:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;)
FIXER TAILLE BLOB($blob;0)
Boucle ($a;1;Taille tableau($MOTS))
TEXTE VERS BLOB($MOTS{$a}+" ";$blob;UTF8 texte sans longueur;
)
Fin de boucle
$PRO_MOTSCLES{$i}:=BLOB vers texte($blob;UTF8 texte sans longueur)

Fin de boucle
$T3:=Nombre de millisecondes-$T3

C_OBJET($OB;$OBVIDE)
TABLEAU OBJET($TAB_OB;1)
$T4:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
Boucle ($a;1;Taille tableau($MOTS))
OB FIXER($TAB_OB{$i};$MOTS{$a};$a)
Fin de boucle
$TAB_OB{$i}:=$OBVIDE
Fin de boucle
$T4:=Nombre de millisecondes-$T4

C_OBJET($OB;$OBVIDE)
TABLEAU OBJET($TAB_OB;1)
$T5:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
$OB:=$OBVIDE
Boucle ($a;1;Taille tableau($MOTS))
OB FIXER($OB;$MOTS{$a};$a)
Fin de boucle
$TAB_OB{$i}:=$OB
$TAB_OB{$i}:=$OBVIDE
Fin de boucle
$T5:=Nombre de millisecondes-$T5

ALERTE("Elem. tablo : “+Chaîne($T1)+”\rVariable locale : “+Chaîne($T2)+”\rBlob : “+Chaîne($T3)+”\rElemn Tab OB : “+Chaîne($T4)+”\rOBJET : "+Chaîne($T5))

</code 4D>

Salut Marc,
évite la boucle de concaténation :
<code 4D>
Boucle($a;1;Taille tableau($MOTS))
$champ:=$champ+$MOTS{$a}+" "
Fin de boucle
</code 4D>
En gros, chaque petit bout de texte ajouté va prendre plus de temps que le précédent, s’il y en a beaucoup, ça devient la catastrophe. Tu peux remplacer, au choix :
• par https://forums.4d.com/Post/FR/15873353/1/15873354#17457534Str_implode>
• la fonction [url=]concat> dans les nouvelles commandes (je n’ai pas fait de tests avec, pas plus que je n’arrive à la retrouver dans la doc :oops:)

: Arnaud DE MONTARD

• la fonction [url=]concat> dans les nouvelles commandes (je n’ai pas
fait de tests avec, pas plus que je n’arrive à la retrouver dans la
doc :oops:)
Voilà http://livedoc.4d.com/4D-Langage-17-R3.1730/Liste-alphabetique-des-commandes.902-3905848.fr.html?&letter=3concat>, mais ça n’est pas la concaténation que je pensais. Celle qui assemble une collection en chaine est http://livedoc.4d.com/4D-Langage-17-R4/Collections/collectionjoin.305-4055278.fr.htmljoin>.

Je me dis qu’on a intérêt à vite se mettre à ce nouveau langage avant qu’il ne devienne aussi bavard que l’ancien…

: Arnaud DE MONTARD

Salut Marc,
évite la boucle de concaténation :
<code 4D>
Boucle($a;1;Taille tableau($MOTS))
$champ:=$champ+$MOTS{$a}+" "
Fin de boucle
</code 4D>
En gros, chaque petit bout de texte ajouté va prendre plus de temps
que le précédent, s’il y en a beaucoup, ça devient la catastrophe. Tu
peux remplacer, au choix :
• par
https://forums.4d.com/Post/FR/15873353/1/15873354#17457534Str_implod

• la fonction [url=]concat> dans les nouvelles commandes (je n’ai pas
fait de tests avec, pas plus que je n’arrive à la retrouver dans la
doc :oops:)

C’est toujours moins rapide que la variable texte locale, mais nettement mieux que l’élement de tableau !

  • Var locale = 46
  • implode = 158
  • elem. Tableau = 890

si j’ai correctement fait le test …
<code 4D>
C_TEXTE($champ)
C_BLOB($blob)
C_ENTIER LONG($i;$u;$a)

TABLEAU TEXTE($PRO_MOTSCLES;100000)

$qT:=0
Si (Mode compilé)
$qt:=1000
Sinon
$qt:=1000
Fin de si
TABLEAU TEXTE($PRO_TEXTE;1)

$txt:=“Bourg-en-Bresse 01 AVALANCHE nettoyage 01000 Réparation automobile de véhicules automobiles légers: entretien courant, Nettoyage courant des bâtiments, SARL unipersonnelle . Ain 01 5 Rue des CRETS”
AJOUTER À TABLEAU($PRO_TEXTE;$txt)
$i:=1
//%R-

$T1:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
Boucle ($a;1;Taille tableau($MOTS))
$PRO_MOTSCLES{$i}:=$PRO_MOTSCLES{$i}+$MOTS{$a}+" "
Fin de boucle
Fin de boucle
$T1:=Nombre de millisecondes-$T1

$T2:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
$champ:=""
Boucle ($a;1;Taille tableau($MOTS))
$champ:=$champ+$MOTS{$a}+" "
Fin de boucle
$PRO_MOTSCLES{$i}:=$champ
Fin de boucle
$T2:=Nombre de millisecondes-$T2

$T3:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;)
FIXER TAILLE BLOB($blob;0)
Boucle ($a;1;Taille tableau($MOTS))
TEXTE VERS BLOB($MOTS{$a}+" ";$blob;UTF8 texte sans longueur;
)
Fin de boucle
$PRO_MOTSCLES{$i}:=BLOB vers texte($blob;UTF8 texte sans longueur)

Fin de boucle
$T3:=Nombre de millisecondes-$T3

C_OBJET($OB;$OBVIDE)
TABLEAU OBJET($TAB_OB;1)
$T4:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
Boucle ($a;1;Taille tableau($MOTS))
OB FIXER($TAB_OB{$i};$MOTS{$a};$a)
Fin de boucle
$TAB_OB{$i}:=$OBVIDE
Fin de boucle
$T4:=Nombre de millisecondes-$T4

C_OBJET($OB;$OBVIDE)
TABLEAU OBJET($TAB_OB;1)
$T5:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
$OB:=$OBVIDE
Boucle ($a;1;Taille tableau($MOTS))
OB FIXER($OB;$MOTS{$a};$a)
Fin de boucle
$TAB_OB{$i}:=$OB
$TAB_OB{$i}:=$OBVIDE
Fin de boucle
$T5:=Nombre de millisecondes-$T5

TABLEAU TEXTE($PRO_TEXTE;0)
AJOUTER À TABLEAU($PRO_TEXTE;$txt)

$T6:=Nombre de millisecondes
Boucle ($u;1;$qt)
TABLEAU TEXTE($MOTS;0)
LIRE MOTS CLÉS TEXTE($txt;$MOTS;*)
$PRO_MOTSCLES{$i}:=Str_implode (->$MOTS;" ")
Fin de boucle
$T6:=Nombre de millisecondes-$T6

//%R+

ALERTE("Elem. tablo : “+Chaîne($T1)+”\rVar locale : “+Chaîne($T2)+”\rBlob : “+Chaîne($T3)+”\rElemn Tab OB : “+Chaîne($T4)+”\rOBJET : “+Chaîne($T5)+”\rimplode : "+Chaîne($T6))

</code 4D>

Je ne me suis pas mis encore aux collections …:oops:

Merci @Arnaud :smiley: ^^

Il faut, comme tu le dis, tester a chaque fois selon la longueur de concaténation, car si la chaine devient longue (plus de mots a concatener), la vitesse peut vite s’écrouler avec une variable texte, et du coup, utiliser implode est la meilleure solution !! :smiley:

Bonjour Marc,

Ce code peut il etre optimisé à votre avis ?
<code 4D>
LIRE MOTS CLÉS TEXTE($Text;$tMotCleDoc)
$n2:=Taille tableau($tMotCleDoc)
Si ($n2>300)
$n2:=300 //On limite le nombre de mots clés à rechercher
Fin de si

			CHERCHER PAR ATTRIBUT([Suggestion];[Suggestion]Mots_Cles;"Mots[]";=;$tMotCleDoc{1};*)
			Boucle ($ens;1;$n2)
				CHERCHER PAR ATTRIBUT([Suggestion]; | ;[Suggestion]Mots_Cles;"Mots[]";=;$tMotCleDoc{$ens};*)
			Fin de boucle 
			CHERCHER([Suggestion])

</code 4D>

: Marc LONGO

Il faut, comme tu le dis, tester a chaque fois selon la longueur de
concaténation
Je ne teste pas, j’utilise (quasi) systématiquement Str_implode : je sais que c’est efficace quand le nombre de concaténations est grand, et quand il est faible je m’en fiche puisqu’il n’y a presque rien à gratter.

: Marc LONGO

Je ne me suis pas mis encore aux collections …:oops:
Un petit exemple pour tester comment ça s’écrit avec une collection :
<code 4D>
$sep_t:=","
$txt_t:=Str_loremIpsum (MAXENT*5) //$1=longueur du lorem ipsum
LIRE MOTS CLÉS TEXTE($txt_t;$mot_at)
C_COLLECTION($mot_c)
$mot_c:=Créer collection
TABLEAU VERS COLLECTION($mot_c;$mot_at)
ASSERT(Taille tableau($mot_at)=$mot_c.length)
$txt_t:=$mot_c.join($sep_t)
$mot_c:=Séparer chaine($txt_t;$sep_t)
$count_l{1}:=$count_l{1}+1
</code 4D>
Cela dit, sur un grand nombre de mots, il ne faut pas en attendre du mieux tant que https://forums.4d.com/Post/FR/27219206/1/27219207#27219207Séparer chaine> fait la roue de la mort.