Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Bonjour à tous,
J'ai un lenteur dans une fonction que je dois l'optimiser. Le lenteur est dû à 2 boucles FOR sur plusieurs nbre des lignes.
Ce traitement permet de construire un fichier cible à partir dans une datawindow adw_source en respectant une format cible parametrable et qui se trouve dans la datawindow dw_format_cible.
NB : la construction du fichier se fait dans le traitement 3 et dans traitement 2 on fait le remplissage d'une datawindow cible qui sera utilisé par la suite pour traitement 3.
ll_jmax = dw_source.RowCount () //(5000 lignes) li_imax = dw_format_cible.RowCount () //(200 lignes) // Pour chaque colonne FOR li_i = 1 TO li_imax // traitement 1 // Pour chaque ligne FOR ll_j = 1 TO ll_jmax // traitement 2 NEXT NEXT // traitement 3
Ce traitement prend 35 minutes et moi, je suis obligé de diminuer le traitement à max 15 minutes.
Quelqu'un a une idée de comment faire l'optimisation.
Merci d'avance
Dernière modification par mattdamon (02-09-2010 09:57:54)
Hors ligne
Bonjour
Qu'est ce qui prend du temps ?
Les 2 boucles et/ou le traitement 3
Certainement les boucles 5000*200 = 1000000...
Hors ligne
erasorz a écrit:
Bonjour
Qu'est ce qui prend du temps ?
Les 2 boucles et/ou le traitement 3
Certainement les boucles 5000*200 = 1000000...
Les 2 boucles FOR qui prennent de temps pas le traitement 3. J'ai mis point d'arret juste à la fin du boucle et début traitement 3 et j'ai remarqué que le lenteur est dû aux 2 boucles. Mais pas de grand chose dans le traitement 1 et 2.
Hors ligne
Bonjour,
Lorsqu'on traite des datawindows en boucle et que chaque boucle introduit un rafraîchissement de l'affichage, le temps de traitement peut s'allonger considérablement.
En général, il est conseiller de positionner le SetRedraw à FALSE de chaque datawindow faisant l'objet d'un traitement dans une boucle et de le repositionner à TRUE en sortie de la boucle.
Ex :
dw_1.SetRedraw(FALSE) FOR li_i = 1 TO 100000 dw_1.DeleteRow(li_i) NEXT dw_1.SetRedraw(TRUE)
Ce traitement sans le setredraw à FALSE peut prendre plusieurs minutes, avec un setredraw à FALSE, il ne prend plus que quelques secondes.
Hors ligne
buck a écrit:
Bonjour,
Lorsqu'on traite des datawindows en boucle et que chaque boucle introduit un rafraîchissement de l'affichage, le temps de traitement peut s'allonger considérablement.
En général, il est conseiller de positionner le SetRedraw à FALSE de chaque datawindow faisant l'objet d'un traitement dans une boucle et de le repositionner à TRUE en sortie de la boucle.
Ex :Code: pb
dw_1.SetRedraw(FALSE) FOR li_i = 1 TO 100000 dw_1.DeleteRow(li_i) NEXT dw_1.SetRedraw(TRUE)
Ce traitement sans le setredraw à FALSE peut prendre plusieurs minutes, avec un setredraw à FALSE, il ne prend plus que quelques secondes.
Merci pour la rapide réponse, je vais tester ça toute suite et je vous tiens au courant.
Hors ligne
En essyant la solution de Buck, j'ai rien gagné. C'est la même durée
Une autre piste ?
Hors ligne
mattdamon a écrit:
Une autre piste ?
Difficile à dire sans voir les traitements 2 et 3.
Hors ligne
Peut tu préciser ce que tu fais (quelles commandes) dans tes boucles
Hors ligne
Yanis a écrit:
Peut tu préciser ce que tu fais (quelles commandes) dans tes boucles
Voici le code de la fonction :
integer li_rowRegleCible, li_len, li_i, li_imax long ll_jmax, ll_j string ls_valeur, ls_col, ls_conversion, ls_defaut, ls_fonction, ls_type string ls_destroy boolean lb_inseree, lb_interrompre integer li_ret // ecriture logfile uf_write_logfile(gf_get_texte_message ("INTMAJCBL", {""})) ll_jmax = adw_source.RowCount () li_imax = idw_format_cible.RowCount () idw_regle.Retrieve (as_regle) gf_msg_ouvre ("INTERFEXP", {""}, 0) idw_format_cible.SetRedraw(FALSE) idw_regle.SetRedraw(FALSE) // Pour chaque colonne FOR li_i = 1 TO li_imax IF gf_action_avec_stop_interrompre (1) THEN // envoi dans logfile erreur maj uf_write_logfile(gf_get_texte_message ("INTSTOPTR", {""})) RETURN -1 END IF gf_msg_compteur (li_i * 100 / li_imax) ls_type = idw_format_cible.GetItemString (li_i, "type") li_len = idw_format_cible.GetItemNumber (li_i, "longueur") // recherche colonne source li_rowRegleCible = idw_regle.Find & ("cible = '" + Trim (idw_format_cible.GetItemString (li_i, "code")) + & "'", 1, idw_regle.RowCount ()) // Si la colonne est déclarée IF li_rowRegleCible > 0 THEN ls_col = idw_regle.GetItemString (li_rowRegleCible, "source") ls_conversion = idw_regle.GetItemString (li_rowRegleCible, "conversion") ls_defaut = idw_regle.GetItemString (li_rowRegleCible, "defaut") ls_fonction = idw_regle.GetItemString (li_rowRegleCible, "fonction") lb_interrompre = gf_string_to_boolean (idw_regle.GetItemString (li_rowRegleCible, "interrompre_err")) adw_source.SetRedraw(FALSE) adw_cible.SetRedraw(FALSE) // Pour chaque ligne FOR ll_j = 1 TO ll_jmax IF NOT lb_inseree THEN // création row de dw_cible adw_cible.InsertRow (0) // Mettre à jour le N° de ligne adw_cible.SetItem (ll_j, "exclude_field_line", ll_j) END IF li_ret = uf_transfo (ll_j, li_i, as_sens, ls_col, ls_conversion, & ls_defaut, ls_fonction, lb_interrompre, ls_valeur, al_errcode, & al_errrow, as_errtext, adw_source, atr_cible) IF as_errtext <> "" THEN // envoi dans logfile erreur maj uf_write_logfile(gf_get_texte_message ("INTERR1", {String (al_errrow), & String (al_errcode), as_errtext})) END IF IF li_ret < 0 THEN RETURN -1 IF NOT Isnull (ls_valeur) AND ls_valeur <> "" THEN // Tronquer à la longueur déterminée dans le format IF Left (ls_type, 4) = "char" THEN IF li_len < 0 OR Isnull (li_len) THEN ls_type = adw_cible.Describe (ls_col + ".coltype") li_len = Integer (Mid (ls_type, 6, Len (ls_type) - 6)) END IF IF li_len > 0 THEN & ls_valeur = Left (ls_valeur, li_len) END IF // affection colonne cible IF uf_affect_data (adw_cible, ll_j, li_i, ls_valeur, ls_type, lb_interrompre) = -1 THEN uf_write_logfile(gf_get_texte_message ("INTERR1", {String (ll_j), & "Column error [" + String (li_i) + "]" , " : " + ls_valeur})) IF lb_interrompre THEN RETURN -1 END IF END IF NEXT adw_source.SetRedraw(True) adw_cible.SetRedraw(True) // On a inserer toutes les lignes cible lors du traitement // de la 1ere colonne OK lb_inseree = TRUE ELSE IF as_typeSortie = "B" THEN ls_destroy += " Destroy COLUMN " + guo_dw.uf_dw_nom_colonne (adw_cible, li_i) idw_format_cible.SetItem (li_i, "code", Null_string) END IF END IF NEXT idw_format_cible.SetRedraw(true) idw_regle.SetRedraw(true) IF gf_est_texte (ls_destroy) THEN adw_cible.Modify (ls_destroy) gf_msg_ferme () RETURN 1
Dernière modification par mattdamon (02-09-2010 12:09:57)
Hors ligne
Enlève les SetRedraw dans la boucle.
gf_action_avec_stop_interrompre (1) dans la boucle => c'est pour permettre à l'utilisateur d'arrêter le traitement ? (Yield...)
Hors ligne
erasorz a écrit:
Enlève les SetRedraw dans la boucle.
gf_action_avec_stop_interrompre (1) dans la boucle => c'est pour permettre à l'utilisateur d'arrêter le traitement ? (Yield...)
Le Yield() existe dans la fonction :gf_action_avec_stop_interrompre (1), donc pas la peine de la mettre une autre fois.
J'ai enlevé le SetRedraw de la boucle, mais la même chose...
Hors ligne
mattdamon a écrit:
Le Yield() existe dans la fonction :gf_action_avec_stop_interrompre (1), donc pas la peine de la mettre une autre fois.
J'ai enlevé le SetRedraw de la boucle, mais la même chose...
mets gf_action_avec_stop_interrompre en commentaire, le Yield te bouffe bcp de temps
pour le setredraw c'est plus parce que c'est inutile dans la boucle...
Hors ligne
Une petite remarque : lors de lancement du traitement, il y a une barre de progression (gf_msg_compteur (li_i * 100 / li_imax)) pour montrer l'état d'avancement. j'ai remarqué la barre avance rapidement jusqu'au 60% (duré 9 minutes) puis ralente (40 % dans 25 minutes). c'est bizarre non ? l'InsertRow dans la deuxième boucle a une effet sur la génération après l'avancement de 60% ?
Hors ligne
Qu'est-ce qu'il y a dans tes deux fonctions "uf_transfo" et "uf_affect_data" ? Les lenteurs viennent peut-être de là ?
Le plus simple serait de logger les temps de traitements de chacunes des étapes (après l'insertRow, après le Find, après chacune des fonctions...) pour voir celle qui consomme le plus.
Hors ligne
Bonjour matt,
Lance un profiler sur tes traitements sous PB: Tu pourras repérer très rapidement
la ou les lignes de codes qui coûtent le plus.
Pour rappel:
Outils de debug et tuning sous PB
Hors ligne
Aloneg a écrit:
Qu'est-ce qu'il y a dans tes deux fonctions "uf_transfo" et "uf_affect_data" ? Les lenteurs viennent peut-être de là ?
Le plus simple serait de logger les temps de traitements de chacunes des étapes (après l'insertRow, après le Find, après chacune des fonctions...) pour voir celle qui consomme le plus.
Effectivement, le lenteur est dû à la focntion uf_transfo () qui fait appel à une autre fonction qui est très compliqué (boucle for de 1 --> 90 + curseur à l'extérieur de la boucle et qui exécute une requete dynamique)
Pour info, le temp consommé est du aux boucles FOR qui se trouvent et surtout l'appel à cette fonction (200 x 5000 fois)
foon a écrit:
Bonjour matt,
Lance un profiler sur tes traitements sous PB: Tu pourras repérer très rapidement
la ou les lignes de codes qui coûtent le plus.
Pour rappel:
Outils de debug et tuning sous PB
Je vais tester au moins la configuration que tu proposes, afin de pouvoir optimiser dans la focntion : uf_transfo ()
Dernière modification par mattdamon (03-09-2010 14:24:52)
Hors ligne