Tutoriel optimisations avancées

Soyez le premier à donner votre avis sur cette source.

Snippet vu 19 972 fois - Téléchargée 36 fois

Contenu du snippet

Voici une liste de modification de codes pour optimiser vos applications. Présenté sous forme de "avant-après", ces optimisations sont pour ceux qui recherche la performance et non pas la lisibilité!! (quitte à casser les conventions...)

Attention, n'oubliez jamais qu'un code compilé sera toujours plus rapide qu'un code interprété.

Les optimisations présentées ci-dessous sont des échantillons, à adapté dans vos situations/algos

Source / Exemple :


'OptCode

'tuto pour les fous

'Ces optimisations sont sensible lorsque le code est compilé.
'Il est probable qu'en mode interprété, les "Après" soit plus lent que "Avant"

'Pas de copyright (et puis quoi encore ! :p )

' ====== DEFS ======

DefLng A-Z
    'DefType : Au lieu de faire Dim i As Long, j As Long, ...
    '... il suffra de faire Dim i, j

Option Base 1
    'ReDim MonTablo(1 to MaVal) pourra être écrit ...
    'ReDim MonTablo(MaVal)
    
Option Explicit
    'Obligation de faire des "Dim" pour chaque variable ...
    'Evitant ainsi d'utiliser le type Variant, très lent!

Option Compare Binary
    'La Comparaison binaire est la plus rapide.
    'S'utilise avec InStr(), InStrRev(), Replace() ...

Option Private Module
    'Tout les subs, functions et declares sont sous-entendu "Private"

' ====== TESTS ======

'Avant
If b = 27 Then
    a = True
Else
    a = False
End If

'Après
Dim a As Boolean
a = (b = 27)

'Avant
If b = 27 And g < 50 Or (c * b > 250) Then
    a = True
Else
    a = False
End If

'Après
Dim a As Boolean
a = (b = 27 And g < 50 Or (c * b > 250))

'Avant
If b >= 0 And b < 255 Then
    a = 32767
End If

'Après (à utilisé avec précaution)
If (b And 255) = b Then
    a = 32767
End If

'Avant
For i = 1 To 5000
    If i > 4000 Then
        a = a + 2
    Else
        a = a + 1
    End If
Next i

'Après (le test qui sera "True" le plus souvent dois être le premier, si possible)
For i = 1 To 5000
    If i <= 4000 Then
        a = a + 1
    Else
        a = a + 2
    End If
Next i

'RAPPEL :
' - au niveau assembleur, les opérations booléennes se font en 1 instruction
'   c'est donc très rapide, plus rapide que les tests.
'   Mais pour profiter de cette rapidité, il faut compiler le programme!
' - l'instruction GOTO est très performante, converti en assembleur!

' ====== TEXTES ======

'Avant
g$ = Left(Trim(Str$))

'Après
Dim g As String
g = Left$(Trim$(Str$))

'Avant
For i = 1 To 100
    txt$ = txt$ & "toto"
Next i

'Après (si on connais la longeur finale de txt$)
txt$ = Space$(Len("toto") * 100)
For i = 1 To 400 Step 4
    Mid$(txt$, i, 4) = "toto"
Next i

'Avant
t = InStr(1, g$, "toto", vbTextCompare)

'Après
t = InStr(1, g$, "toto", vbBinaryCompare)

'Encore Après
Option Compare Binary
Dim t As Long
t = InStr(1, g$, "toto", -1) 'vbUseCompareOption

'RAPPEL :
' - certaines fonctions de manipulation de chaine existe en mode binaire.
'   LeftB(), RightB(), MidB(), InStrB()
'   Sachant que les chaines String$ sont sur 2 octets (unicode), cela peut
'   être utile lorsque on manipule la mémoire via pointeur plutôt que la
'   valeur... (comprenne qui pourra!)
' - Avant de coder une fonction de manipulation de chaine, vérifiez qu'elle
'   n'existe pas déjà!
'   Space$(),String$(),Trim$(),LTrim$(),RTrim$(),LSet,Rset
'   StrComp(),InStrRev(),Replace(),Split(),Filter(),StrConv(),StrReverse()

' ====== OBJETS ======

'Avant
Dim Bvv As New MaClasseQueJaiFait
Bvv.Init
Bvv.Param1 = 254
Bvv.Param2 = "toto"

'Après
Dim Bvv As New MaClasseQueJaiFait
With Bvv
    .Init
    .Param1 = 254
    .Param2 = "toto"
End With

'Avant
For i = 1 To Len(Text1.Text)
    g$ = g$ & Mid$(Text1.Text, i, Len(Text1.Text) - i + 1)
Next i

'Après (version 1)
Dim i As Long, l As Long, tx1 As String
tx1 = Text1.Text
l = Len(tx1)
For i = 1 To l
    g$ = g$ & Mid$(tx1, i, l - i + 1)
Next i

'Après (version 2)
Dim i As Long
With Text1
    For i = 1 To Len(.Text)
        g$ = g$ & Mid$(.Text, i, Len(.Text) - i + 1)
    Next i
End With

'Avant
Dim MaCollection() As MaClasseTruc
'[...]
For i = 1 To UBound(MaCollection())
    MaCollection(i).Truc = Machin
    MaCollection(i).FonctionBidule Param1
    If MaCollection(i).Tata = True Or MaCollection(i).Titi = True Then
        MaCollection(i).VazyGo
    End If
Next i

'Après
Dim MaCollection() As MaClasseTruc
'[...]
For i = 1 To UBound(MaCollection())
    With MaCollection(i)
    .Truc = Machin
    .FonctionBidule Param1
    If .Tata = True Or .Titi = True Then
        .VazyGo
    End If
    End With
Next i

'Avant
Dim Momo As MaClasseIci
Dim Mimi As MaClasseParam
'[...]
If Momo.Totoz(Mimi.Valeur(Index1)) = 1 Then
    Call FonctionQuiGere(Momo.Totoz(Mimi.Valeur(Index1)))
End If

'Après
Dim Momo As MaClasseIci
Dim Mimi As MaClasseParam
'[...]
Dim MaVal As Long
MaVal = Momo.Totoz(Mimi.Valeur(Index1))
If MaVal = 1 Then
    Call FonctionQuiGere(MaVal)
End If

' RAPPEL :
' - appeler une variable ou une fonction d'un objet oblige a appelé
'   un gestionnaire d'objets (c'est lent)
' - mieux vaux utiliser un maximum de modules / un minimum d'objets
'   ou encore un objet avec beaucoup de fonctions Private, le rendant autonome
' - les OCX sont des objets encore plus lent que des classes, car externe au projet.
' - DirectX et ses affiliés sont des objets, et s'optimise très bien avec ces astuces.

' ====== ALGOS DIVERS ======

Sub DecomposeRGB(Couleur As Long)
    'Avant (maths)
    cb = Int(Couleur / 65536)
    cg = Int((Couleur - cb * 65536) / 256)
    cr = Couleur - cg * 256 - cb * 65536

    'Après (bitmask)
    cb = Couleur And 255&
    cg = (Couleur And &HFF00&) / 256&
    cr = (Couleur And &HFF0000) / &H10000
End Sub

'Avant
For i = 1 To 150000

Next i

'Après (vitesse a vérifier en benchmark post-compilatoire : varie selon l'algo)
Dim i As Long
i = 1
Do While i <= 150000

i = i + 1
Loop
' nota : très utile lorsque vous devez imbriquer des boucles.

'Avant
Sub Wait(Duree As Single)
    t1 = Timer + Duree
    Do While Timer < t1
    Loop
End Sub

'Après (selon besoins de préçision)
Declare Sub Sleep Lib "kernel32" (ByVal DureeMS As Long)
Sub Wait2(Duree As Single)
Dim t1 As Single
    t1 = Timer + Duree
    Do While Timer < t1
        DoEvents  '<= evite de bloquer le système
        Sleep 1&  '<= libère le CPU pendant 1 milliseconde (évite de chauffer)
    Loop
End Sub

'Avant
For i = 1 To 10000
    t = t + i * Sqr(5)
Next i

'Après (précalcul)
sq = Sqr(5)
For i = 1 To 10000
    t = t + i * sq
Next i

'Avant (on peut remplacé lbound() par 1 si on connais le plus petit index de la liste)
Dim MaListe() As Long
Dim MaCopie() As Long
'[...]
ReDim MaCopie(LBound(MaListe()) To UBound(MaListe()))
For i = LBound(MaListe()) To UBound(MaListe())
    MaCopie(i) = MaListe(i)
Next i

'Après (on est pas limité par le type de la destination)
Declare Sub RtlMoveMemory Lib "kernel32" (ByRef Destination As Any, ByRef Origine As Any, ByVal Longueur As Long)
Dim MaListe() As Long
Dim MaCopie() As Long
'[...]
Dim l As Long
l = UBound(MaListe()) - LBound(MaListe()) + 1
ReDim MaCopie(1 To l)
RtlMoveMemory MaCopie(1), MaListe(LBound(MaListe())), l * 4  '4 octets par entrée

'RAPPEL :
' - Précalculez les valeurs avant les boucles si c'est possible
' - L'utilisation du masque de bits fait parti des astuces de
'   programmation impossible a réaliser avec des mathématiques
' - l'API RtlMoveMemorty permet de faire des manipulations de
'   données en mémoire, c'est un outil puissant qui fait défaut
'   à VB alors qu'il existe dans les autres langages (memcpy en C)
' - la fonction vb VarPtr() couplé à l'API su-cité permet de
'   compensé l'absence de pointeur (comme en C)!

' ====== FONCTIONS VB6 PEU UTILISEES ======

'Pour récupérer le dossier temporaire de windows, le dossier système, ...
'peut varié selon l'OS utilisé (win98, win2k, ...)
DossierTemp$ = Environ("TMP")
DossierTemp$ = Environ("TEMP")
ExePathDefault$ = Environ("PATH")
DossierWin$ = Environ("WINDIR")

'Connaitre le type d'une variable (débogage)
MonType$ = TypeName(MaVar)

'Arrondi au nombre de décimal souhaité
MaValInt2 = Round(MaValPrecise, 2)

'Gestion d'erreur
'Classique :
Sub MaFunc()
On Error Resume Next 'ignore l'erreur
End Sub

Sub MaFunc2()
'Approfondi :
On Error GoTo Gere
'[...]
Exit Sub
Gere:
    'gestion
Resume 'retourne a la ligne source d'erreur
End Sub

'RAPPEL : il vaux mieux faire des tests pour éviter les erreurs plutôt que de laissé On Error gérer l'erreur

'Fonction dans une fonction
'L'interêt est qu'appelé (Call) une fonction est plus lent que faire un GOTO
Sub Truc()
'[...]
GoSub algotemp
'[...]
Exit Sub
algotemp:
    '[...]
Return
End Sub

'E/S Fichier
'vous connaissiez :
Close
'pour fermer tout les fichiers ouvert ?
'il existe également :
Reset
'Qui... fait pareil :)

'Utiliser un masque pour comparer des chaines de caractères
b = (MaChaine Like MonMasque)
'autre écriture autorisé :
If MaChaine Like MonMasque Then
'démo :
MaChaine$ = "pomme": Masque$ = "p?m*"
'alors b = True ...

' ====== ASTUCE ======

'Affichage de l'état / progression d'une fonction
'Avant
For i = 1 To 10000
    Label1.Caption = Format$(i / 100, "#0") & "%"
    DoEvents
    Call SubMachin(UnTruc(i))
Next i

'Après
For i = 1 To 10000
    If i Mod 100 = 0 Then
        Label1.Caption = Format$(i / 100, "#0") & "%"
        DoEvents
    End If
    Call SubMachin(UnTruc(i))
Next i
'nota : on évite de rafraichir en permanence l'affichage, ce qui gaspille BEAUCOUP de temps-machine
'dans l'exemple "après", on le rafraichit toutes les 100 itérations

Conclusion :


Ces astuces sont presque "obligatoire" si on veux faire des jeux en VB.

Rajoutez vos astuces en commentaire!

A voir également

Ajouter un commentaire

Commentaires

Messages postés
4172
Date d'inscription
mercredi 30 juillet 2003
Statut
Membre
Dernière intervention
9 juin 2006
21
JoePatent < Je suis tout a fait d'accord avec toi ! Il est posible que 12 lignes de code soient pus rapide que 4 ! Mais à vitesse égal, je préfère les 4 lignes.
Excuses-moi encore d'avoir écorner tes propos !
sans rancune ?
Messages postés
608
Date d'inscription
samedi 3 août 2002
Statut
Membre
Dernière intervention
22 décembre 2016

Restez zen ...
C'est de l'optimisation ... pour une bonne vie et une
bonne collectivité.

Allez bonne prog à tous

Afyn - Navedac
Messages postés
171
Date d'inscription
jeudi 30 janvier 2003
Statut
Membre
Dernière intervention
20 juillet 2008

crenaud76 ->"Alors allez jusqu'à dire qu'un code est plus lisible s'il comporte plus de ligne, j'en suis pas sur du tout. Moi, je préfère 4 lignes bien claire que 12 trop longues !!! "

Ca ne repond pas a la premisse de depart. OPTIMISATION signifie avoir un gain de performance.

Tes 4 lignes sont-elles plus performantes que les 12 lignes ? Si il n'y a pas de difference, pourquoi mettre ca dans un TUTORIEL d'optimisation.

Si tu veux me citer, fais le comme du monde ! voici ce que j'ai dit : "Tu ne gagne rien a procéder de la sorte, tu as juste moins de ligne mais aussi moins de clareté."

Où vois-tu "pas lisible du tout" dans cet extrait hors contexte ?

N'importe quoi...
Messages postés
4172
Date d'inscription
mercredi 30 juillet 2003
Statut
Membre
Dernière intervention
9 juin 2006
21
Je viens de découvrir ce tuto, et je reviens sur l'histoire d'utiliser les With et End With ou pas !
Je n'ai jamais désassembler une source VB de ma vie, mais je peux dire que tous les tests que j'ai pu faire sur le sujet (optimisation de la vitesse du code) m'ont amener à penser que With ... End With fait toujours gagner du temps ! Et encore plus si on le sort des boucles, bien sûr !! Et les imbrications de With ... End With sont aussi avantageuses.
Pour finir, je reviendrais aussi sur le cas de ceci ...

'Avant
If b = 27 Then
a = True
Else
a = False
End If

'Après
Dim a As Boolean
a (b 27)

JoePatent trouve la solution 'Après' pas du tout lisible !! Moi cela me parle bien ! Peut-être est-ce parce que j'ai fait du C avant le VB et que a = (b==27) est totalement lisible en C et que le fait que l'opérateur d'affectation et celui de comparaison de l'égalité sont identique en VB, contrairement à ceux du C !! Ce qui en soit est déjà une entrave à la bonne lisibilité du code VB, mais on va pas réinventé VB maintenant !! Alors allez jusqu'à dire qu'un code est plus lisible s'il comporte plus de ligne, j'en suis pas sur du tout. Moi, je préfère 4 lignes bien claire que 12 trop longues !!! Cela reste une affaire de goût. L'important c'est que si tu maintiens ton propre code, il te faut adopter une ligne de conduite (pour pondre des lignes de code, justement) qui te convienne et si tu maintiens du code de groupe ou qu'un groupe maintient ton code, il faut impérativement que le groupe se mette d'accord avant de pondre la moindre ligne de code.
sinon je met un 10/10 au tuto, même si comme certain, je connaissait la plupart des astuces (certaines on toutefois retenu toute mon attention !!!)
Messages postés
17286
Date d'inscription
mercredi 2 janvier 2002
Statut
Modérateur
Dernière intervention
23 décembre 2019
62
étrange, en effet... tu gagnerais davantage, je pense, en ne recalculant pas tout le temps QBColor(4)...(bien que ce ne soit pas l'objet de ta demonstration)
Afficher les 28 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.