violent_ken
Messages postés1812Date d'inscriptionmardi 31 mai 2005StatutMembreDernière intervention26 octobre 2010
-
2 sept. 2005 à 19:04
PCPT
Messages postés13272Date d'inscriptionlundi 13 décembre 2004StatutMembreDernière intervention 3 février 2018
-
4 sept. 2005 à 22:09
Violent Ken
Salut. Je suis en train de faire un algorithme de calcul, et j'aimerais l'optimiser au maximum.
Par exemple, est-il plus rapide de faire
for x=1 to 10
a=a+30
next x
ou
for x=1 to 30
a=a+10
next x
est-il plus rapide de faire
if a=1 then
else
end if
ou d'utiliser Iif
est-il plus rapide de faire
While a < 500
a = a + 1
Wend
ou
Do Until a = 500
a = a + 1
Loop
a=b^0.5 ou a=sqr(b)
Il y a des tas de possibilités pour faire une même action, et j'aimerais que vous me donniez des astuces pour pouvoir 'optimiser' au maximum le code.
Merci, @+
Note: je sais que le C est bien plus rapide que le VB, mais je compte faire mon algo en VB
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 2 sept. 2005 à 19:30
pour tes exemples de boucles for, aucune (désolé).
Quand tu peux faire le même traitement en décrémentant vers 0, c'est toujours la meilleure.
Raison de cela:
for x=1 to 10
a=a+30
next x
compilo mettra un truc de ce genre:
mov eax, 1 ; EAX = x, le compteur
lblFOR:
add edx, 30
inc eax
cmp eax, 10 ; ICI INSTRUCTION STUPIDE, faute du developpeur
jne short lblFOR
Si tu fais avec un do while i <> 0
mov eax, 10
lblWHILE:
add edx, 30
dec eax
jne short lblWHILE
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 2 sept. 2005 à 19:44
là c'est évident, on n'appelle pas en boucle la même fonction qui recevra le même param, clair qu'il faut mettre dans une variable le résultat.
Pour le reste il y a peu à faire, en vb tu as très peu prise sur le code produit par le compilo.
cs_DARKSIDIOUS
Messages postés15814Date d'inscriptionjeudi 8 août 2002StatutMembreDernière intervention 4 mars 2013130 2 sept. 2005 à 20:01
Ben le plus simple, c'est de tester par toi même :
Tu fait une fonction pour chaque type d'optimisation que tu veux faire,
et tu l'appelle un bon milliers (voir un bon million) de fois, et tu
compare le temps mis pour éxécuter la boucle de la première fonction
avec la boucle pour executer la deuxième fonction, et tu répète ceci
plusieurs fois, ca te donneras déjà une idée de quelle fonction est la
plus rapide.
DarK Sidious
Un API Viewer (pour le VB, VB.NET, C, C# et Delphi) : www.ProgOtoP.com/popapi/
CMD_Start.Enabled = True
End Sub
'
'
Private Sub CMD_Start_Click()
Dim i As Long
Dim MoyenneMs As Currency, Mess As String
CMD_Start.Enabled = False
MoyenneMs = 0
For i = 0 To NbBoucles
LBL_EnCours.Caption = i + 1 & " sur " & NbBoucles + 1
AfTimer.Enabled = True
Call MaProc
AfTimer.Enabled = False
TabTest(i) = AfTimer.Value
If TabTest(i) > MaxRes Then MaxRes = TabTest(i)
If TabTest(i) < MinRes Then MinRes = TabTest(i)
DoEvents
Next i
For i = 0 To NbBoucles
MoyenneMs = MoyenneMs + TabTest(i)
Next i
End Sub
'
'
Private Sub MaProc()
'ta procédure
End Sub
il ne faut pas oublier, pour être très précis, que l'appel, mêem vide, de la procédure, est une action qui prend aussi sont temps....
tu peux donc saisir ta procédure directement à l'endroit ou tu fais l'appel (les clicks)
voici quelques traces :
<HR>
Private Sub MaProc()
Dim x As Integer, a As Integer
For x = 1 To 10
a = a + 30
Next x
End Sub
Nombre de Test : 1000
Vitesse min = 0,0824ms
Vitesse max = 5,0811ms
moyenne = 0,1175ms
<HR>
Private Sub MaProc()
Dim a As Integer
a = 0
While a < 500
a = a + 1
Wend
End Sub
Nombre de Test : 1000
Vitesse min = 0,0833ms
Vitesse max = 21,1695ms
moyenne = 0,153ms
<HR>
Private Sub MaProc()
Dim a As Integer
a = 0
Do Until a = 500
a = a + 1
Loop
End Sub
Nombre de Test : 1000
Vitesse min = 0,0824ms
Vitesse max = 5,0811ms
moyenne = 0,1175ms
<HR>
nb : évidemment, AfTimer dispo dans mes sources
PCPT
us_30
Messages postés2065Date d'inscriptionlundi 11 avril 2005StatutMembreDernière intervention14 mars 201610 2 sept. 2005 à 22:07
Entièrement d'accord avec DaksiDious...
Les tutos sur le sujet sont assez bien fait, en général et se recoupe très souvent... Mais il reste encore des choses à dire... Par exemple, sur les boucles FOR, il est préférable de déclarer la variable de la boucle (souvent pas fait), surtout lorsque la variable rentre dans un calcul (souvent le cas) afin d'éviter de passer par le type Variant (toujours à proscrire pour la rapidité)... Voici un exemple illustrant la chose...
=
Sub essai()
temps = Timer
Dim t As Long 'Déclaration : Variable de la boucle
Dim a As Long
For t = 1 To 20000000
a = t
Next t
MsgBox "La durée du test : " & Timer - temps & " seconde(s)"
cs_CanisLupus
Messages postés3757Date d'inscriptionmardi 23 septembre 2003StatutMembreDernière intervention13 mars 200621 2 sept. 2005 à 22:21
Salut, il manque un avis sur le :
if a=1 then
else
end if
ou d'utiliser Iif
Je n'ai pas testé la diff entre les 2 mais a priori, Iif est une fonction donc sans doute plus gourmande qu'un simple if .. then ...else...
D'autre part, penser à la maintenance, il se peut qu'on veuille rajouter 1 ou plusieurs instructions dans dans le if et/ou dans le else et le Iif n'est pas prévu pour ça.
Je rajouterai qu'il y a aussi les if...elseif....elseif....else... et dans ce cas, (en vb6) je préfère le select case que je pense plus rapide et plus simple à maintenir.
-------------------------------------------------
Dresseur de puces, .... normal pour un loup !?
violent_ken
Messages postés1812Date d'inscriptionmardi 31 mai 2005StatutMembreDernière intervention26 octobre 20102 2 sept. 2005 à 22:34
Violent Ken
Merci pour tout ces conseils, j'apprécie bcp.
Je vais moi même tester mes procédures, surtout qu'apparemment la pseudo-meilleure-rapidité d'un while/wend face à un do/until dépend des instructions contenues dans la boucle.
En tout cas, merci beaucoup
@+
us_30
Messages postés2065Date d'inscriptionlundi 11 avril 2005StatutMembreDernière intervention14 mars 201610 2 sept. 2005 à 22:42
Pour le IIF, c'est moins rapide que IF ELSE, car toutes la fonction est analysé... donc avec : IIF ( condition , resultat si vrai, resultat si faux) : les trois paramètres sont passés en revue... contrairement à IF qui s'arrêterait si la condition est vraie, ou saute directement à ELSE dans le cas contraire... Bon, enfin tous ceci est expliqué dans l'aide de VB... où il préconise pas l'emploi IIF si on cherche à aller vite...
Mais voilà, perso, je trouve plus clair un code sur une ligne comme IIF, que les multiples lignes... bon, donc entre rapidité et clarté d'un code ?... faut choisir...
ET pour DO ?...
LE plus rapide c'est d'utiliser :
DO
LOOP condition
et DO...LOOP est toujours plus rapide que WHILE/WEND...
Ceci dit, je pense qu'on est pas prêt de tarir le sujet...
violent_ken
Messages postés1812Date d'inscriptionmardi 31 mai 2005StatutMembreDernière intervention26 octobre 20102 2 sept. 2005 à 23:11
Violent Ken
us_30, "l'étude" http://www.vbfrance.com/code.aspx?ID=25985 semble te donner raison pour les do/loop , while/wend (quoique, c'est pas évident)
Quant aux Select Case, il me paraissent plus lent que les if/then/else/end if
Et les ElseIf, je ne sais pas trop, je ne les utlilise jamais (à tort ?)
@+
PCPT
Messages postés13272Date d'inscriptionlundi 13 décembre 2004StatutMembreDernière intervention 3 février 201847 2 sept. 2005 à 23:17
a = 1 2 3 ou 4
Select case a
case 1:...
case 2:...
case 3:...
case 4:...
end select
if a=1 then
...
elseif a=2 then
...
elseif a = 3 then
...
else
....
endif
je modifie un peu mon code ci dessus (Aftimer). en effet, je n'ai pas pris en compte que le fait de faire le test lui même, prend des ressouces, faussant donc les résultats
cs_CanisLupus
Messages postés3757Date d'inscriptionmardi 23 septembre 2003StatutMembreDernière intervention13 mars 200621 2 sept. 2005 à 23:20
Tiens, puisqu'on cause de boucles (for ... next, do ... while, etc ...), un ptit DoEvents dans une boucle assez longue (en vb6) est souvent nécessaire.
C'est sans doute une instruction supplémentaire pour le processeur mais, en gros, ça lui dit qu'il peut reprendre la main pour exécuter d'autres tâches pendant que les opérations contenues dans la boucle ne le mobilisent pas.
Un avis différent ?
-------------------------------------------------
Dresseur de puces, .... normal pour un loup !?
violent_ken
Messages postés1812Date d'inscriptionmardi 31 mai 2005StatutMembreDernière intervention26 octobre 20102 2 sept. 2005 à 23:27
Violent Ken
Pour le cas du doevents, prenons le cas d'une boucle simple
For x=1 to 100000
L(x)=in(rnd*10)+1
next x
(tient d'ailleurs, y parait que ne pas mettre le x ne change pas grand chose, à voir)
Faut-il songer à mettre un doevents ?
A première vue non, puisque cette instruction ralentit considérablement la performance de calcul. Mais faut-il envisager une ligne du genre :
if (x mod 1000)=0 then doevents
Et est-ce que çà change qqchose de mettre
if ( x mod 1000)=0 then
ou bien, if not(x mod 1000) then
?
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 2 sept. 2005 à 23:33
DoEvents n'engendre pas qu'une instruction, c'est très gros en traitement. Dans tous les cas, pas moyen de faire un thread en vb alors faut s'en contenter.
PeekMessage
TranslateMessage
DispatchMessage
us_30
Messages postés2065Date d'inscriptionlundi 11 avril 2005StatutMembreDernière intervention14 mars 201610 2 sept. 2005 à 23:40
Ah tiens ! je dérive un peu... Dans mon algo sur la multiplication de grand nombre, pour l'optimisation, j'ai été obligé de sortir un calcul une fois tous les 90 boucles... avec un truc semblable : if X mod 90 = 0 then ... J'avais planché un peu dessus pour trouver mieux... mais sans succès... si qlq'un trouve un truc mieux, s'y preneur...
(A noter que le test X mod... est exécuté dans une boucle, donc testé à chaque passage...)
Bon... pour en revenir à la dernière remarque de ViolentKen... une interruption, une fois tous les X fois, cela me semble une bonne idée pour pas trop pénaliser le traitement avec DoEvents...
PCPT
Messages postés13272Date d'inscriptionlundi 13 décembre 2004StatutMembreDernière intervention 3 février 201847 2 sept. 2005 à 23:50
y'a pas à chier, il faut un DoEvents. et pas que tous les 1000 fois.
il suffit de tenter de déplacer une fenêtre pendant sa boucle durant un doevents, on voit vite pourquoi c'est indispensable !
NOT implique 2 calculs. il sera toujours plus long, mais plus "propre" en lecture de source
Const NbBoucles As Long = 999 '999
Dim TabTest(NbBoucles) As Currency
Dim MinRes As Currency
Dim MaxRes As Currency
'
'
Private Sub Form_Load()
AfTimer_Proc.TypeTimer = BenchMark
AfTimer_Wait.TypeTimer = Classical
CMD_Start.Enabled = False
LBL_EnCours.Caption = ""
End Sub
'
'
Private Sub CMD_Init_Click()
CMD_Init.Enabled = False
AfTimer_Proc.Enabled = True
Call MaProc
AfTimer_Proc.Enabled = False
MinRes AfTimer_Proc.Value: MaxRes AfTimer_Proc.Value
AfTimer_Wait.Interval = Int(MinRes) * 2
CMD_Start.Enabled = True
End Sub
'
'
Private Sub CMD_Start_Click()
CMD_Start.Enabled = False
AfTimer_Wait.Enabled = True
End Sub
'
'
Private Sub AfTimer_Wait_Timer()
AfTimer_Proc.Enabled = True
Call MaProc
AfTimer_Proc.Enabled = False
End Sub
'
'
Private Sub AfTimer_Proc_BenchResult(WhichApi As String, Result As Currency)
Static Cpt As Long
LBL_EnCours.Caption = Cpt + 1 & " sur " & NbBoucles + 1
TabTest(Cpt) = Result
If TabTest(Cpt) > MaxRes Then MaxRes = TabTest(Cpt)
If TabTest(Cpt) < MinRes Then MinRes = TabTest(Cpt)
Cpt = Cpt + 1
If Cpt = NbBoucles + 1 Then
AfTimer_Wait.Enabled = False
Call FinTest
End If
End Sub
'
'
Private Sub FinTest()
Dim i As Long
Dim MoyenneMs As Currency, Mess As String
MoyenneMs = 0
CMD_Start.Enabled = True
For i = 0 To NbBoucles
MoyenneMs = MoyenneMs + TabTest(i)
Next i
us_30
Messages postés2065Date d'inscriptionlundi 11 avril 2005StatutMembreDernière intervention14 mars 201610 3 sept. 2005 à 16:32
Euh... à minuit tout le monde dort...
JE ne suis pas entièrement d'accord avec toi, sur deux points.
Pour DoEvents déjà. Tu dis qu'il le faut le mettre à chaque fois, pour permettre un déplacement de la fenêtre... Bon ok, mais pour moi, je conçois plus le DoEvents, pour que l'utilisateur puisse changer d'application, réduire la fenêtre ou arrêter la procédure en cours... Donc, c'est des actions qui n'ont pas besoin d'être testées en permanence... IL me semble, que si l'utilisateur lance un long calcul (pour peu qu'on l'informe), qu'il n'a pas besoin d'avoir en permanence la possibilité de déplacer la fenêtre de l'application... On parle d'optimisation, il faut revenir au sujet... Le DoEvents est évidemment une fonction à l'opposé d'une optimisation. Trouvé un moyen entre le besoin de convivialité et la performance, est nécessairement un compromis... et comment rendre cette contrainte acceptable ? ...la solution proposé par Violent Ken, me semble déjà intéressante...
Ma deuxième remarque, est sur ton code... L'idée est bien. Mais... Perso, je préfère utiliser ma façon, même si trop manuel. C'est à dire, mettre le compteur juste au début et juste à la fin de la partie de code à tester, évitant ainsi tout intermédiaire... déjà, parce que je peux mieux évaluer la différence (en pourcentage) entre deux façons de procéder... bon, ceci dit, quand on regarde les remarques pour ce genre de tests, on voit toujours que la première discorde se situe finalement sur le "protocole" pour tester... c'est peut-être déjà la première chose à bien définir... Perso, au vu du post précédent de BruNews, je pense que le meilleur c'est effectivement d'étudier le codage résultant en ASM, pour voir le plus court... mais, là je ne sais plus faire...
PCPT
Messages postés13272Date d'inscriptionlundi 13 décembre 2004StatutMembreDernière intervention 3 février 201847 3 sept. 2005 à 16:59
salut'
(mon post de minuit n'est que la correction de celui de 22h )
sans parler du fait de déplacer la fenêtre, prenons encore plus simple :
ouvre le gestionnaire des tâches (ou une appli avec jauge processeur)
fait une boucle sur 1million et pendant le travail, ferme l'appli (bouton fermer, ou un bouton UnLoad),
et regarde ce qui ce passe dans la jauge.
quand au fait d'appeler la procédure (test) directement, c'est bien ce que j'ai écris au départ.
"il ne faut pas oublier, pour être très précis, que l'appel, mêem vide, de la procédure, est une action qui prend aussi sont temps....
tu peux donc saisir ta procédure directement à l'endroit ou tu fais l'appel (les clicks)"
là, c'est uniquement pour une question de lisibilité. de plus, rien empêche de décompter le temps d'appel de la procédure vide....
toujours est-il que çà peut être bien pratique pour comparer efficacement les différences de temps de calculs, ce qui me semble être la question de départ...