Quoi, tu ne connais pas PB ? Va falloir parcourir tout le forum alors !

Le forum (ô combien francophone) des utilisateurs de Powerbuilder.

Recherche rapide

Annonce

Certaines rubriques, dont des cours, sont uniquement visibles par les membres du forum ^^.
Dans la rubrique Liens & Références, vous avez accès à un sommaire de téléchargement, profitez-en !
Il existe maintenant un nouveau TOPIC "Votre CV en Ligne" accessible uniquement par demande.

#1 02-09-2010 09:56:36

mattdamon  
Le Tuniso-Parisien
Lieu: Livry-Gargan 93190
Date d'inscription: 29-12-2007
Messages: 569
Pépites: 89
Banque: 77,512,666,613,392,940

Optimisation dans 2 boucles FOR

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.

Code: pb

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

 

#2 02-09-2010 10:05:58

erasorz  
Admin
Lieu: Babylone
Date d'inscription: 23-11-2006
Messages: 5121
Pépites: 97,197
Banque: 2,147,483,647

Re: Optimisation dans 2 boucles FOR

Bonjour
Qu'est ce qui prend du temps ?
Les 2 boucles et/ou le traitement 3
Certainement les boucles 5000*200 = 1000000...


N'envoyez jamais un humain faire le travail d'un programme.

Hors ligne

 

#3 02-09-2010 10:16:10

mattdamon  
Le Tuniso-Parisien
Lieu: Livry-Gargan 93190
Date d'inscription: 29-12-2007
Messages: 569
Pépites: 89
Banque: 77,512,666,613,392,940

Re: Optimisation dans 2 boucles FOR

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

 

#4 02-09-2010 10:23:18

buck  
Modérateur
Lieu: Dijon
Date d'inscription: 31-07-2008
Messages: 747
Pépites: 1,028,843
Banque: 171,170,849,654

Re: Optimisation dans 2 boucles FOR

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.

Hors ligne

 

#5 02-09-2010 10:25:52

mattdamon  
Le Tuniso-Parisien
Lieu: Livry-Gargan 93190
Date d'inscription: 29-12-2007
Messages: 569
Pépites: 89
Banque: 77,512,666,613,392,940

Re: Optimisation dans 2 boucles FOR

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

 

#6 02-09-2010 11:43:58

mattdamon  
Le Tuniso-Parisien
Lieu: Livry-Gargan 93190
Date d'inscription: 29-12-2007
Messages: 569
Pépites: 89
Banque: 77,512,666,613,392,940

Re: Optimisation dans 2 boucles FOR

En essyant la solution de Buck, j'ai rien gagné. C'est la même durée

Une autre piste ?

Hors ligne

 

#7 02-09-2010 11:55:17

erasorz  
Admin
Lieu: Babylone
Date d'inscription: 23-11-2006
Messages: 5121
Pépites: 97,197
Banque: 2,147,483,647

Re: Optimisation dans 2 boucles FOR

mattdamon a écrit:

Une autre piste ?

Difficile à dire sans voir les traitements 2 et 3.


N'envoyez jamais un humain faire le travail d'un programme.

Hors ligne

 

#8 02-09-2010 11:56:33

Yanis  
Modérateur
Lieu: paris
Date d'inscription: 16-06-2010
Messages: 349
Pépites: 665
Banque: 150

Re: Optimisation dans 2 boucles FOR

Peut tu préciser ce que tu fais (quelles commandes) dans tes boucles

Hors ligne

 

#9 02-09-2010 12:07:37

mattdamon  
Le Tuniso-Parisien
Lieu: Livry-Gargan 93190
Date d'inscription: 29-12-2007
Messages: 569
Pépites: 89
Banque: 77,512,666,613,392,940

Re: Optimisation dans 2 boucles FOR

Yanis a écrit:

Peut tu préciser ce que tu fais (quelles commandes) dans tes boucles

Voici le code de la fonction :

Code: pb

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

 

#10 02-09-2010 12:36:47

erasorz  
Admin
Lieu: Babylone
Date d'inscription: 23-11-2006
Messages: 5121
Pépites: 97,197
Banque: 2,147,483,647

Re: Optimisation dans 2 boucles FOR

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...)


N'envoyez jamais un humain faire le travail d'un programme.

Hors ligne

 

#11 02-09-2010 12:59:51

mattdamon  
Le Tuniso-Parisien
Lieu: Livry-Gargan 93190
Date d'inscription: 29-12-2007
Messages: 569
Pépites: 89
Banque: 77,512,666,613,392,940

Re: Optimisation dans 2 boucles FOR

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

 

#12 02-09-2010 13:02:49

erasorz  
Admin
Lieu: Babylone
Date d'inscription: 23-11-2006
Messages: 5121
Pépites: 97,197
Banque: 2,147,483,647

Re: Optimisation dans 2 boucles FOR

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...


N'envoyez jamais un humain faire le travail d'un programme.

Hors ligne

 

#13 02-09-2010 13:31:42

mattdamon  
Le Tuniso-Parisien
Lieu: Livry-Gargan 93190
Date d'inscription: 29-12-2007
Messages: 569
Pépites: 89
Banque: 77,512,666,613,392,940

Re: Optimisation dans 2 boucles FOR

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

 

#14 03-09-2010 06:57:22

Aloneg  
Membre Geek
Date d'inscription: 14-02-2007
Messages: 30
Pépites: 1,182
Banque: 37,934,892,619

Re: Optimisation dans 2 boucles FOR

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

 

#15 03-09-2010 07:21:47

foon  
N2iGeek + MangasGeek = foon
Award: bf
Lieu: Bonchamp-Lès-Laval
Date d'inscription: 28-02-2007
Messages: 2486
Pépites: 85
Banque: 9,223,372,036,854,776,000

Re: Optimisation dans 2 boucles FOR

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


Seuls ceux qui ne font rien ne font jamais d'erreurs
http://www.nerdtests.com/images/badge/163124fb7fb459a3.gif

Hors ligne

 

#16 03-09-2010 14:24:04

mattdamon  
Le Tuniso-Parisien
Lieu: Livry-Gargan 93190
Date d'inscription: 29-12-2007
Messages: 569
Pépites: 89
Banque: 77,512,666,613,392,940

Re: Optimisation dans 2 boucles FOR

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

 

Pied de page des forums

Propulsé par FluxBB 1.2.22