Optimiser un programme en visual basic 6

Optimiser un programme en Visual Basic 6

Introduction

Qu'est-ce qu'optimiser ?

En latin, l'adverbe optime, superlatif de bene, signifie « de façon excellente, le mieux du monde ». Optimiser a donc quelque chose à voir avec l'excellence. En informatique, il s'agit bien sûr des performances. On dit qu'un programme est optimisé lorsque le programmeur a pesé une à une toutes les lignes (ou presque) de son code pour ne garder que leur écriture la plus efficace. L'optimisation est donc aussi affaire de nuances. Ce tutoriel se veut une brève introduction à l'optimisation avec Visual Basic 6.

Optimiser n'est pas suffisant

La chose la plus importante de ce tutoriel tient en une phrase : l'optimisation ne remplace pas la réflexion. Pourquoi ? La réponse est simple. Lorsque vous rédigez un programme et que vous en venez à évaluer ses performances, vous verrez que certaines parties sont cruciales en termes de performances. En règle générale, il ne suffit pas d'optimiser ces parties pour obtenir de bonnes performances. Il faut aussi, et avant tout, s'assurer que l'algorithme utilisé est raisonnable. Cela passe souvent par une analyse (ou même une évaluation approximative) de sa complexité en temps et / ou en mémoire. Par exemple, un banal tri par insertion, qu'il soit brut ou optimisé, sera toujours beaucoup plus lent qu'un tri rapide, même programmé par un cochon. Ceci dit, ne me faites pas dire ce que je n'ai pas dit : l'optimisation n'est pas sans effet, bien au contraire ! Nous allons d'ailleurs voir ce qu'elle peut nous apporter par la suite.

Optimiser n'est pas défigurer

Autre chose importante, si les programmes ne s'écrivent qu'une seule fois, ils sont en revanche souvent lus, aussi bien par le programmeur lui-même que par des tiers. De fait, l'optimisation doit toujours être vue comme un compromis entre accroissement des performances et lisibilité du programme. En d'autres termes, il peut être judicieux d'ajouter des commentaires là où des optimisations ont été effectuées, surtout lorsqu'elles introduisent une manière de faire peu « naturelle » ou non « immédiate ». Songez bien que si cela ne vous a pas paru évident, cela l'est probablement encore moins aux yeux du programmeur qui découvre votre code.

Quand optimiser ?

Dernier point avant d'aborder l'optimisation proprement dite : quand faut-il optimiser son code ? A l'évidence, il n'existe pas de règle infaillible pour répondre à cette question. En revanche, on se tire d'affaire sans problème en réfléchissant un peu : certaines optimisations devraient devenir des réflexes (je pense notamment aux déclarations, au symbole dollar, etc... dont je vais parler plus loin) et se retrouver partout, alors que d'autres peuvent très bien être considérées comme facultatives lorsque le programme ne se doit pas d'être particulièrement efficace (sauf erreur, tous les programmes n'ont pas besoin d'être des bêtes de course... surtout en Visual Basic).

Quelques règles pour optimiser

Maintenant que cette longue et pénible introduction est terminée, nous allons pouvoir parler de choses plus concrètes. Que peut-on faire pour optimiser son code ? Je ne vais pas tout détailler pour deux raisons : d'une part ce serait trop long, et d'autre part il faudrait que j'en sache beaucoup plus sur Visual Basic. Nous allons donc nous contenter des notions élémentaires.

Le langage

Certes, s'agissant de VBFrance, nous allons parler d'un langage, Visual Basic. Cela dit, il n'est peut-être pas inutile de rappeler qu'il existe des langages plus rapides que d'autres, car leurs compilateurs sont plus performants. Par exemple, les trois versions d'un même programme « bien rédigé », l'une en C, l'autre en Java et la troisième en Visual Basic, ne nécessiteront pas le même temps d'exécution sur une même machine. Cela dit, laissons tomber ce point qui ne rentre que partiellement dans le cadre de ce site consacré à un langage particulier et venons-en à l'essentiel.

Typage

Contrairement à ce que l'on pourrait croire, il ne suffit pas de déclarer « As Integer » un ensemble de variables pour que toutes soient définies comme des entiers. Même si cela peut paraître rébarbatif, il faut déclarer toutes les variables. Par exemple :

Mauvaise écriture :

Dim Minimum, Maximum As Integer   

Ecriture correcte :

Dim Minimum As Integer, Maximum As Integer

Évidemment, ce qui s'applique aux entiers s'applique à tous les autres types. Il ne faut pas oublier que Visual Basic considère que toute variable sans type explicite est de type Variant. Avec ce type polymorphe, rien (ou presque) n'est bon : vous réduisez les performances de votre application, et vous vous exposez à de déplaisantes erreurs de typage ou, à défaut, à des conversions implicites qui pèsent beaucoup sur votre code.

Les mathématiques

Même si les profs de maths sont des personnes rarement adorées, la discipline qu'ils enseignent peut vous apporter une aide précieuse. Par exemple, comment savoir si un entier est pair (en anglais : even number) ? Il existe de très nombreuses manières de procéder. La première fait appel à un semblant de partie entière :

'Détermine si un nombre est pair 
Public Function IsNumberEven(Number As Long) As Boolean
    IsNumberEven = ((Number \ 2) = (Number / 2))
End Function

Cette programmation est tout simplement abominable. Sur le plan mathématique, elle relève déjà du non-sens. Si on fait de l'arithmétique sur N ou sur Z, pourquoi faire intervenir une loi de composition (dite externe) dont le résultat n'est ni dans N ni dans Z ? Allez, ressaisissons-nous et proposons autre chose. Voilà déjà quelque chose de plus inspiré :

'Détermine si un nombre est pair 
Public Function IsNumberEven(Number As Long) As Boolean
    IsNumberEven  = (Number Mod 2 =  0) 
End Function 

Notre nouvelle fonction IsNumberEven est certes plus performante que la première, mais est-elle pour autant la meilleure ? Hélas, la réponse est non. Il est en effet plus rapide encore de tirer parti de la propriété mathématique suivante : « tout nombre pair écrit en binaire se termine par un zéro ». C'est simple : 2 s'écrit 10, 4 s'écrit 100, 6 s'écrit 110, etc... (et cela se généralise). Allons-y donc franchement et savourons notre victoire (même dérisoire, une victoire est toujours une victoire) :

'Détermine si un nombre est impair 
Public Function IsNumberEven (Number As Long) As Boolean
    IsNumberEven = ((Number And 1) = 0) 
End Function 

Il existe un autre cas relativement simple où les calculs bit à bit (ou bitwise operations pour les fanatiques d'anglais) sont plus efficaces que les fonctions mathématiques usuelles. Il s'agit du calcul des composantes rouge, verte et bleue à partir d'un entier :

'Détermine les composantes rouge, verte et bleue d'une couleur 
Public Sub GetRGBFromLong(ByVal Color As Long, Red As Byte, Green As Byte, Blue As Byte) 
    Red  = Color And &HFF 
    Green =  (Color \ &H100) And &HFF 
    Blue = (Color \&H10000) And &HFF 
End Sub

De tels calculs peuvent parfois paraître obscurs (ils le sont sans doute pour ceux qui ne sont pas familiers avec les opérations bit à bit), mais Google est un dieu puissant et généreux... ;-) Je vous conseille tout particulièrement http://edais.mvps.org/Tutorials/Graphics/GFXch5.html (en anglais).

Le symbole dollar

Optimiser, c'est gagner du temps. Et le temps, c'est de l'argent. Alors pensez au symbole dollar ! Au-delà de cette blague vaseuse, il existe de nombreuses fonctions Visual Basic qui méritent d'être affublées d'un tel symbole. Cela vous permettra d'obtenir une valeur de retour sous forme de chaîne de caractères, au lieu d'un affreux Variant. Ainsi, il peut être préférable d'écrire :

Left$, Mid$, Right$, Chr$, ChrW$, UCase$, LCase$, LTrim$, RTrim$, Trim$, Space$, String$, Format$, Hex$, Oct$, Str$, Error$

Attention !

Il est inutile de transformer le recours au symbole dollar en véritable obsession. Par exemple, il est inutile d'écrire Replace$ (ou InputBox$) car Replace renvoie déjà une chaîne de caractères (ceux qui ne le croient pas n'ont qu'à regarder l'infobulle qui apparaît dans Visual Basic lors de la saisie de la parenthèse ouvrante). Maintenant, si vous trouvez que Replace$ est plus joli, je ne vais pas vous contredire...

Dim BadThing As New HowToMakeAProgramRunSlowly

Derrière ce titre volontairement fantaisiste se cache quelque chose qui n'a rien d'une plaisanterie. Le mot-clef « New » indique à Visual Basic que la variable déclarée doit être automatiquement instanciée . De fait, chaque fois que vous l'utiliserez, Visual Basic vérifiera si elle doit être instanciée ou non (avec toutes les répercussions que cela implique sur les performances). De plus, si vous souhaitez bien contrôler toutes les étapes, préférez :

'Déclaration 
Dim Something As SomethingElse 

'Instanciation 
Set Something  = New SomethingElse 

'Libération de la mémoire 
Set Something =  Nothing

Plutôt If ou plutôt IIf ?

S'il est bien une fonction que l'on devrait apprendre à ne pas aimer exclusivement (Attention ! Je n'ai pas écrit : « à ne pas aimer tout court »), c'est bien la fonction Immediate If , mieux connue sous son nom usuel « IIf ». Non seulement cette fonction peut jouer de vilains tours à ceux qui l'utilisent (voir la source de Renfield - http://www.vbfrance.com/code.aspx?ID=33789), mais elle est aussi caractérisée par sa lenteur. Lorsqu'il est nécessaire d'optimiser son code, il vaut mieux lui préférer la structure classique.

Par exemple, la fonction Min suivante :

Public Function Min(A As Long, B As Long) As Long
    Min =   IIf(A < B, A, B) 
End Function 

sera toujours plus lente que son équivalent :

Public Function Min(A As Long, B As Long) As Long
    If A < B Then
        Min = A 
    Else
        Min = B 
    End If
End Function

Le mot-clef Like

Le mot-clef Like offre une souplesse indéniable. Certes, il n'égale pas les expressions rationnelles (loin s'en faut), mais tout de même... il est « sympa ». Seulement, là où le bât blesse, c'est qu'il est aussi plutôt lent. Autant que possible, préférez-lui les fonctions classiques associées aux chaînes de caractères (InStr, InStrB, etc...).

Une chaîne vide demande un temps plein

Les chaînes vides s'écrivent souvent sous la forme de deux guillemets disposés en chiens de faïence. C'est très court à écrire, mais c'est plus long que nécessaire. Il vaut mieux remplacer :

Dim MySlowEmptyString As String MySlowEmptyString = ""

par :

Dim ThisIsFast As String ThisIsFast = vbNullString 

N'allons cependant pas trop vite. En réalité, la chaîne vide (empty string) et la chaîne nulle (null string) sont deux choses bien distinctes. Une chaîne vide est une chaîne, alors qu'une chaîne nulle n'est pas une chaîne. En C, vbNullString est l'équivalent de NULL.

Réaliser des mesures de temps

Pour effectuer des mesures exploitables, il est fortement recommandé de ne pas utiliser de minuterie (Timer), dont la précision est de l'ordre de 50 millisecondes et de ne pas effectuer vos mesures dans l'IDE mais dans un exécutable. Vous pouvez utiliser les API GetThickCount ou le duo QueryPerformanceCounter / QueryPerformanceFrequency. Dans tous les cas, il vaut mieux exécuter plusieurs fois (des dizaines, des centaines voire des milliers de fois) la fonction à l'intérieur d'une boucle plutôt que de se contenter d'un appel. A toutes fins utiles, voici leurs déclarations :

Private Type LARGE_INTEGER
    LowPart As Long
    HighPart As Long
End Type

'Evaluer le temps d'exécution d'un programme 

Private Declare Function QueryPerformanceCounter Lib "kernel32" ( _ 
   lpPerformanceCount As LARGE_INTEGER) As Long  

'Fréquence du compteur de Windows
Private Declare Function QueryPerformanceFrequency Lib "kernel32" ( _ 
   lpFrequency As LARGE_INTEGER) As Long  

'Evaluer le temps d'exécution d'un programme 
Private Declare Function GetTickCount Lib "kernel32" Alias "GetTickCount" () As Long 

Conclusion

Optimiser son code n'est ni une nécessité ni un remède miraculeux. Les programmes qui reposent sur des algorithmes à la complexité aberrante seront toujours poussifs. Les programmes bien conçus n'y gagneront que s'il y a vraiment matière à gagner quelque chose. Comme toujours, la conclusion est désarmante de simplicité : un bon programme est un programme bien pensé. Voilà tout ! J'espère avoir fait quelque chose d'utile. Toutes les remarques, critiques, suggestions et corrections sont les bienvenues.

Bah, moi il m'en faut plus !

Ce tutoriel n'est qu'un début... Il existe sur Internet de très nombreuses pages qui vous donneront de plus amples renseignements sur le sujet. Allez voir notamment le site de us_30 (par ICI) et sa rubrique consacrée à l'optimisation de code VBA. Vous y trouverez des mesures comparatives de vitesse et de nombreux autres exemples. Pour les anglophones, vous pouvez consulter les pages pour les chaînes de caractères, mais aussi remarques générales d'optimisation, et ainsi de suite...

Ce document intitulé « Optimiser un programme en visual basic 6 » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Rejoignez-nous