Optimisation des performances dans Visual Basic .NET
Gordon Brown
Microsoft Corporation
Résumé : Cet article est conçu pour aider les développeurs à améliorer les performances d'exécution de leur applications Visual Basic .NET. Cet article contient également des liens vers des pages en anglais.
Sommaire
Introduction
Types
de données
Déclarations
Opérations
Procédures
Optimisations supplémentaires
Conclusions
Introduction
L'un des objectifs principaux de Visual Basic® .NET consiste à obtenir des versions optimisées par rapport aux précédentes. Cependant, les performances restent tributaires du mode de conception de votre programme. Cet article présente certaines remarques importantes vous permettant d'optimiser les performances de votre application. Le reste de cette introduction traite des conditions et des hypothèses sous-jacentes aux recommandations sur l'optimisation.
Langage intermédiaire
Visual Basic .NET et C#™ sont compilés en langage MSIL (Microsoft Intermediate Language). Le code source équivalent dans les deux langues est généralement compilé dans le même code MSIL et entraîne les mêmes performances pour votre application. Les performances ne doivent pas constituer un critère dans le choix des deux langues. Consultez l'article Compiling to MSIL pour obtenir de plus amples informations.
Fréquence d'exécution
Certaines recommandations de cet article peuvent sembler quantité négligeable dans une déclaration, mais peuvent représenter des gains de performances considérables au niveau d'une boucle ou d'une procédure fréquemment appelée. Par conséquent, les blocs de code répétés plusieurs fois sont des candidats parfaits pour l'optimisation.
Goulets d'étranglement
La meilleure approche en matière d'optimisation est d'identifier les goulets d'étranglement ou les parties de votre application qui s'avèrent plus lentes afin d'essayer de les améliorer. Généralement, les boucles trop longues et les accès aux bases de données constituent des goulets d'étranglement. De toute façon, essayer d'optimiser séparément chaque expression et appel de procédure n'est pas du tout efficace en termes d'effort de développement.
Dépendance de l'application
Les performances dépendent en grande partie des caractéristiques de chaque application. Vous n'avez jamais aucune garantie de succès. Les recommandations de cet article ne sont que des conseils. Vous devrez sans doute les adopter pour les besoins particuliers de votre application.
Plate-forme
Visual Studio® .NET est optimisé pour la
configuration matérielle système recommandée,
que ce soit pour l'environnement de développement
intégré (IDE) ou pour le runtime. Si votre
mémoire vive est insuffisante, vous risquez de ne pas
obtenir les performances souhaitées. Ceci s'avère
particulièrement vrai en cas d'application volumineuse ou
d'exécutions simultanées. Consultez l'article
Locating Readme Files
pour
obtenir de plus amples informations et vérifier si votre
système respecte les conditions requises.
Conditions de test
Dans le cadre de cet article, des tests spécifiques ont été effectués à l'aide de Visual Studio .NET 2002 dans Microsoft® Windows® 2000 Professional, sur un ordinateur Pentium III à 600 MHz avec une mémoire vive de 256 Mo. Les tests spécifiques consistaient en des boucles serrées qui avaient seulement pour objet de vérifier les éléments de code comparés. En d'autres termes, les boucles contenaient les éléments de code et rien d'autre. Par conséquent, les différences de minutage représentent les cas les plus extrêmes et vous ne devez pas vous attendre à des différences si importantes dans une application normale.
Informations préliminaires
Cet article est basé sur des informations préliminaires. Nos recommandations sont soumises à modifications compte tenu de la mise à jour et de la précision des informations que procure l'expérience. Certaines remarques sous-jacentes peuvent également changer dans les prochaines versions.
Types de données
Les types de données choisis pour vos variables, propriétés, arguments de procédure et valeurs de retour de procédure peuvent affecter les performances de votre application.
Types de valeurs et types de références
Les types de valeur conservent leurs données dans la mémoire qui leur est allouée. Étant donné que chaque instance d'un type de valeur est isolée et qu'elle n'est pas accessible via plusieurs variables, les types de valeurs peuvent être conservés et gérés sur la pile.
Les types de références conservent uniquement un pointeur vers l'emplacement de la mémoire qui stocke les données. Étant donné que plusieurs variables peuvent pointer vers les données, les types de références peuvent être conservés et gérés sur le tas.
La gestion des tas est plus difficile que l'allocation de piles en matière de performances. Cela représente une charge conséquente en termes d'allocation des tas, d'accès aux objets et d'opération GC (garbage collection). Ceci signifie qu'un type de valeur réduite est préférable à un type de référence lorsque la flexibilité d'un type de référence n'est pas requise. Cependant, les types de valeurs perdent cet avantage lorsqu'ils sont plus importants. Par exemple, effectuer une assignation avec un type de valeur à cinq octets prend plus de temps que l'assignation avec un type de référence.
L'effet du choix du type de données sur les
performances peut tout aussi bien s'avérer
négligeable que représenter un avantage de 30
pourcent en faveur des types de valeur de taille réduite.
Notez que cela dépend également d'autres facteurs,
tels que la plate-forme matérielle, le chargement du
système et la taille des données. Consultez l'article
Value Types and Reference Types
pour
obtenir de plus amples informations.
Type d'objet et liaison tardive
Une variable de type référence déclarée comme Object peut pointer vers des données de tout type. Cependant, cette flexibilité peut compromettre les performances, car une variable Object est toujours à liaison tardive.
Une variable de type référence est à liaison anticipée si elle déclarée comme classe spécifique, telle que Form. Ceci permet au compilateur Visual Basic d'effectuer certaines optimisations au moment de la compilation, telles que la vérification du type et la recherche de membre. Lorsque vous accédez aux membres sur une variable d'objet de liaison anticipée au moment de l'exécution, le compilateur a déjà effectué une grande partie du travail de gestion.
Une variable est à liaison tardive si elle est déclarée comme un type Object ou sans type de données explicite. Lorsque votre code accède aux membres sur ce type de variable, le CLR (common language runtime) doit effectuer la vérification du type et la recherche de membre au moment de l'exécution. Notez que, si Option Explicit est défini sur Off, une variable déclarée sans type de données explicite est de type Object.
Les objets à liaison anticipée sont considérablement plus performants que les objets à liaison tardive. Ils facilitent également la lecture et la maintenance de votre code et réduisent le nombre d'erreurs d'exécution. Ceci signifie qu'en cours de développement, vous devez déclarer les variables de votre objet à l'aide d'un type de classe spécifique lorsque vous le connaissez. Consultez l'article Early and Late Binding pour obtenir de plus amples informations.
Évitez d'utiliser le type Object lorsque cela
n'est pas nécessaire. En plus du problème lié
à la liaison tardive, les variables Object qui
pointent vers les données d'un type de valeur
nécessitent davantage de mémoire, à la fois pour
le pointeur et pour une copie supplémentaire des
données. Consultez l'article
Object Type
pour obtenir de plus amples
informations.
Largeur du type de données
Les types de données les plus efficaces sont ceux qui utilisent la largeur des données natives de la plate-forme run-time. Sur les plate-formes actuelles, la largeur des données est de 32 bits, pour l'ordinateur et le système d'exploitation.
Par conséquent, Integer est actuellement le type de données le plus efficace dans Visual Basic .NET. Long, Short et Byte viennent tout de suite après la classe Integer. Vous pouvez améliorer les performances des classes Short et Byte en désactivant le contrôle de dépassement sur les entiers, par exemple en définissant la propriété RemoveIntegerChecks, mais ceci entraîne le risque de calculs incorrects dus à des dépassements non détectés. Il est impossible de changer ce réglage en cours d'exécution ; vous pouvez uniquement régler cette valeur lors de la prochaine compilation de votre application.
Si vous avez besoin de valeurs fractionnaires, choisissez Double, car les processeurs à virgules flottantes des plate-formes actuelles exécutent toutes les opérations en double précision. Single et Decimal viennent tout de suite après la classe Double.
Unités de représentation
Dans certains cas, votre application peut utiliser des types de données entier (Integer, Long, Short, Byte) au lieu de types fractionnaires. Ceci est souvent le cas lorsque vous pouvez choisir les unités. Par exemple, pour représenter la taille d'une image, vous pouvez utiliser des pixels au lieu de pouces ou de centimètres. Le nombre de pixels dans une image étant toujours un chiffre entier, vous pouvez stocker cette valeur dans une variable Integer. Si vous choisissez des pouces, vous devrez probablement recourir à des valeurs fractionnaires. Vous aurez alors besoin d'une variable Double qui n'est pas aussi efficace. La plus petite unité de représentation peut généralement être un entier, alors que les plus grandes unités sont généralement fractionnaires. Si vous effectuez plusieurs opérations avec ces unités, un type de données entier peut améliorer les performances.
Conversion Boxing et Unboxing
La conversion Boxing est le traitement supplémentaire effectué par le common language runtime lorsque vous traitez un type de valeur comme type de référence. La conversion Boxing est nécessaire, par exemple, si vous déclarez une variable Integer et que vous l'affectez à une variable Object ou que vous la transférez vers une procédure qui nécessite un argument Object. Dans ce cas, le CLR doit effectuer une conversion boxing de la variable pour la convertir en type Object. Il copie la variable, insère la copie dans un objet récemment alloué et stocke les informations liées au type.
Si vous affectez ensuite la variable de type boxed à une variable déclarée comme type de valeur, le CLR doit procéder à une conversion unboxing, c'est-à-dire copier les données de l'instance du tas dans la variable du type de valeur. En outre, la variable de type boxed doit être gérée sur le tas, que la conversion unboxing ait été ou non effectuée.
La conversion Boxing et Unboxing entraîne une dégradation considérable des performances. Si votre application traite fréquemment une variable du type de valeur comme un objet, il est préférable de la déclarer initialement comme type de référence. Une solution consiste à procéder d'abord à une conversion boxing, puis maintenir cette version tant qu'elle est utile et enfin effectuer une conversion unboxing lorsque le type de valeur est à nouveau requis.
Vous pouvez éliminer tout risque de conversion boxing par inadvertance grâce au paramètre Option Strict On. Cela vous aidera alors à localiser les emplacements où effectuer une conversion boxing sur un type de valeur et vous forcera à recourir à la conversion explicite qui est souvent plus efficace que la conversion boxing. Notez, cependant, que vous ne pouvez pas vous passer de la conversion boxing en utilisant à la place la conversion explicite. CObj(<value type>) et CType(<value type>, Object) sont deux méthodes de boxing sur le type de valeur.
Tableaux
Évitez d'utiliser un rang trop important. Plus un tableau est petit, plus il est efficace. La différence est encore plus flagrante entre les tableaux à une ou deux dimensions, car le CLR est optimisé pour une dimension.
Les tableaux en escalier (tableaux de tableaux) sont
actuellement plus efficaces que les tableaux rectangulaires
(multidimensionels). En d'autres termes, A(9)(9) est plus efficace que A(9,9). Ceci est dû au fait que les
tableaux en escalier bénéficient de l'optimisation
des tableaux à une dimension. La différence peut
être supérieure à 30 %.
Notez que les tableaux en escalier ne sont pas compatibles
avec le common language specification (CLS). Ceci signifie que
vous ne devez pas intégrer des tableaux en escalier dans
des classes susceptibles d'accepter du code compatible CLS.
Consultez l'article
Arrays
pour obtenir de plus amples
informations.
ArrayList
La classe ArrayList dans l'espace de noms System.Collections prend en charge un tableau dynamique qui change de taille, si nécessaire. Pour l'utiliser, déclarez une variable avec le type de données ArrayList au lieu d'utiliser la déclaration de tableau standard. Vous pouvez ensuite appeler ses méthodes Add, AddRange, Insert, InsertRange, Remove et RemoveRange pour ajouter et supprimer des éléments.
Si la taille de votre tableau change fréquemment et que
vous devez conserver les valeurs des éléments
existants, l'objet ArrayList peut offrir de meilleures
performances que l'instruction ReDim avec le mot
clé Preserve. L'inconvénient de
ArrayList est que tous ses membres sont de type
Object et sont, par conséquent, à liaison
tardive. Quant à savoir si les avantages de l'instruction
ReDim compensent largement les inconvénients de la
liaison tardive, cela dépend de votre application.
Préparez-vous à essayer les deux approches et à
comparer les performances. Consultez l'article
ArrayList Class
pour
obtenir de plus amples informations.
Déclarations
Comme nous l'avons vu dans la section Type d'objet et Liaison tardive, la liaison anticipée qui est plus rapide que la liaison tardive, facilite également la vérification des erreurs. Vous devez déclarer vos variables Object à l'aide du type de classe le plus spécifique et le plus approprié. Prenez comme exemple la hiérarchie d'héritage partielle de ces classes dans l'espace de noms System.Windows.Forms :
Object
Control
Button
Label
Form
Supposez que vous utilisez une variable Object de telle
sorte que chaque objet que vous lui affectez est de type
Control et que la plupart mais pas tous sont de type
Form. Bien que le type Form soit plus
spécifique que le type Control, vous ne pouvez pas
déclarer la variable en tant que type
System.Windows.Forms.Form, car cela nécessiterait
probablement des objets de type Button ou Label.
Vous devez déclarer la variable en tant que type
System.Windows.Forms.Control, car c'est le type le plus
spécifique qui peut accepter chaque objet qui lui est
affecté. Consultez l'article
System.Windows.Forms Namespace
pour
obtenir de plus amples informations.
Propriétés, variables et constantes
Les variables s'exécutent plus rapidement que les propriétés. Un accès à la variable génère un simple stockage ou extraction de mémoire. Un accès la propriété requiert l'appel de la méthode Get ou Set de cette propriété, qui nécessite parfois un traitement supplémentaire outre l'extraction ou le stockage de la valeur. Notez que le compilateur implémente les variables WithEvents en tant que propriétés, ce qui fait qu'elles ne présentent aucun des avantages de performance des autres variables par rapport aux propriétés.
Les constantes s'exécutent plus rapidement que les variables, car leurs valeurs sont compilées dans le code. Un accès à la constante ne requiert même pas d'extraction de mémoire, sauf pour les constantes de type Date ou Decimal.
Paramétrage des options
Le paramétrage Option Explicit On vous oblige
à déclarer toutes vos variables, facilitant ainsi la
lecture et la maintenance de votre code. Assurez-vous
d'utiliser la clause As dans chaque déclaration, y
compris dans les arguments de procédure. Si vous passez
outre cette recommandation, vos variables et vos arguments
prennent le type de données Object, qui n'est
généralement pas le meilleur type. L'utilisation de
la clause As améliore les performances, car elle
modifie l'inférence du type entre le moment
d'exécution et la compilation. Consultez l'article
Option Explicit Statement
pour
obtenir de plus amples informations.
Le paramétrage Option Strict On interdit le
passage implicite, requiert la clause As dans chaque
déclaration et interdit toute liaison tardive quel que
soit le paramétrage de Option Explicit. Vous pouvez
tout de même effectuer des conversions de type restrictif,
mais vous devez utiliser les mots clés de la conversion
explicite, tels que CInt et CType. La
déclaration explicite améliore les performances, car
elle protège votre code de toute liaison tardive
involontaire. Consultez l'article
Option Strict Statement
pour
obtenir de plus amples informations.
Le paramétrage Option Compare Binary spécifie que les chaînes doivent être comparées et triées en fonction de la représentation binaire de leurs caractères, sans tenir compte des caractères équivalents, tels que les majuscules et les minuscules. Utilisez la comparaison binaire à chaque fois que la logique de votre application vous le permet. Elle améliore les performances car le code n'a pas à gérer l'insensibilité à la casse, ni les groupes de caractères considérés alphabétiquement comme identiques dans une langue donnée.
Collections d'objets et tableaux d'objets
Lorsque vous gérez de la même façon une série d'objets liés, vous pouvez les intégrer dans un tableau d'objets ou vous pouvez créer une collection avec les objets traités en tant que membres. Les remarques suivantes peuvent vous aider à choisir entre ces deux méthodes :
- Le CLR peut optimiser le code pour un tableau, tandis que chaque accès à une collection requiert un ou plusieurs appels à une méthode. Par conséquent, il est recommandé d'utiliser des tableaux lorsqu'ils sont capables de gérer toutes les opérations que vous devez exécuter.
- Pour les accès indexés, les tableaux sont généralement plus rapides que les collections.
- Pour les accès clés, utilisez une collection. Les tableaux ne gèrent pas l'accès à l'aide d'un champ de clé. Vous devez donc écrire le code pour rechercher les éléments du tableau pour la clé.
- Pour des insertions et des suppressions, il est préférable d'utiliser des collections. Les tableaux ne gèrent pas directement l'ajout et la suppression d'éléments. Si vous effectuez une insertion ou une suppression à la fin d'un tableau, vous devez utiliser l'instruction ReDim, qui réduit les performances. Pour effectuer une insertion ou une suppression à un autre endroit, utilisez un objet ArrayList au lieu d'un tableau standard. En revanche, les insertions et les suppressions sont des opérations simples dans une collection et elles sont toutes aussi rapides, quelle que soit la position des éléments impliqués.
E/S du fichier disque
Visual Basic .NET offre trois principales façons d'accéder aux fichiers du disque :
- Les fonctions d'exécution classiques de Visual Basic telles que FileOpen et WriteLine
- Le modèle de l'objet FileSystemObject (FSO) de Microsoft Scripting Runtime
- Le modèle de l'objet .NET Framework dans l'espace de noms System.IO
Les fonctions classiques du fichier exécutable sont fournies pour une compatibilité avec les versions précédentes de Visual Basic. FSO est fourni pour la compatibilité avec les langages de script et pour les applications qui requièrent sa fonctionnalité. Chacun de ses modèles est implémenté comme une série d'objets wrapper qui appelle les membres des classes dans l'espace de noms System.IO. Par conséquent, ils ne sont pas aussi efficaces que l'utilisation directe de System.IO. En outre, le FSO nécessite l'implémentation par votre application de l'interopérabilité COM, ce qui entraîne une charge mémoire de marshaling conséquente.
Vous pouvez améliorer vos performances en utilisant les classes System.IO, comme indiqué ci-dessous :
- Path, Directory et File pour un traitement au niveau du lecteur et du dossier
- FileStream pour la lecture et l'écriture générales
- BinaryReader et BinaryWriter pour les fichiers comportant des données binaires ou inconnues
- StreamReader et StreamWriter pour des fichiers texte
- BufferedStream pour permettre la mise en mémoire tampon d'un flux d'E/S
La classe FileStream offre généralement les performances de disque les plus efficaces. Elle effectue sa propre mise en mémoire tampon et exécute ses propres opérations de disque, intégrant uniquement des procédures d'E/S Windows. Cependant, si les E/S du disque ne présentent pas un goulet d'étranglement dans votre application, l'une des autres classes peut s'avérer plus adaptée. Par exemple, il est possible qu'il soit préférable d'utiliser StreamReader et StreamWriter si vous traitez uniquement du texte et que les performances du disque ne sont pas essentielles.
Mémoires tampon
Réduisez autant que possible la taille de vos mémoires tampon, en particulier lorsque vous utilisez BufferedStream ou FileStream. La taille idéale est généralement de 4 Ko, même si cela peut varier selon l'application. Les mémoires tampon inférieures à 4 Ko peuvent altérer les performances en occasionnant trop d'opérations E/S pour un certain volume de données. Les mémoires tampon trop volumineuses peuvent consommer plus de mémoire que nécessaire pour une augmentation des performances donnée. Selon le matériel utilisé, la limite supérieure raisonnable peut varier de 8 à 64 Ko.
E/S asynchrones
Si votre application est tributaire du disque, vous pouvez profiter de la latence du disque pour exécuter d'autres tâches lorsque vous attendez la fin d'un transfert d'E/S. Pour ce faire, utilisez les E/S asynchrones disponibles avec la classe FileStream. Cette approche peut nécessiter davantage de code source, mais elle optimise les performances de votre exécution car une partie du code s'exécute alors qu'une opération de lecture ou d'écriture est en cours. Si vous transférez un volume important de données ou si la latence de votre disque est importante, l'amélioration risque d'être considérable.
Opérations
L'arithmétique sur les entiers est plus rapide que sur les nombres à virgule flottante ou à décimales. Pour les calculs où les virgules décimales ou les valeurs fractionnaires ne sont pas requises, déclarez toutes vos variables et constantes comme des types de données entier, de préférence Integer. Cependant, gardez à l'esprit que leur conversion depuis ou vers un type de données à virgules flottantes réduit les performances.
Opérateurs
Lorsque vous divisez des valeurs entières, utilisez la division d'entiers (opérateur \) lorsque vous avez uniquement besoin du quotient et non du reste. L'opérateur \ peut être plus de dix fois plus rapide que l'opérateur /.
Opérateurs d'assignation
Les opérateurs d'assignation, tels que +=, sont
plus précis que leurs opérateurs constitutifs
(= et + séparés) et peuvent faciliter
la lecture de votre code. Si vous traitez une expression au
lieu d'une variable simple, par exemple un élément de
tableau, vous pouvez atteindre des performances
considérables avec des opérateurs d'assignation. Ceci
est dû au fait que l'expression, par exemple MyArray(SubscriptFunction(Arg1, Arg2)) ne
doit être évaluée qu'une seule fois.
Concaténations
Utilisez l'opérateur de concaténation (&) plutôt que l'opérateur plus (+) pour concaténer les chaînes. Ils sont équivalents uniquement si les deux opérandes sont de type String. Si ce n'est pas le cas, l'opérateur + devient une liaison tardive et doit effectuer le contrôle du type et les conversions. L'opérateur & est conçu spécifiquement pour les chaînes.
Tests booléens
Lorsque vous testez une valeur Boolean dans une instruction If, la lecture est facilitée si vous spécifiez uniquement la variable dans le test plutôt que d'utiliser l'opérateur = pour la comparer à True. Bien que la différence en termes de performances soit négligeable, le deuxième test de l'exemple suivant représente une meilleure méthode de programmation :
If BoolVariable = True Then ' Spécification non requise de True.
' ...
End If
If BoolVariable Then ' Plus compact.
' ...
End If
...
Court-circuitage
Lorsque cela est possible, utilisez les opérateurs de court-circuitage Boolean, AndAlso et OrElse. Ils peuvent vous faire gagner du temps en vous permettant de court-circuiter l'évaluation d'une expression en fonction du résultat de l'autre expression. Dans le cas de AndAlso, si le résultat de l'expression de gauche est False, le résultat final est déjà déterminé et l'expression de droite n'est pas évaluée. De même, OrElse ignore l'expression de droite si celle de gauche est évaluée sur True. Notez également que l'instruction Case peut court-circuiter une liste des nombreuses expressions et plages si elle trouve une valeur de correspondance avant la fin de la liste.
Accès au membre
Certains accès au membre (opérateur .) appellent une méthode ou une propriété qui renvoie un objet. Dans la classe System.Windows.Forms.Form, par exemple, la propriété Controls renvoie un objet ControlCollection. Un tel accès implique la création d'objet, l'allocation et la gestion des tas et l'exécution d'une GC (garbage collection). Si vous effectuez ce type d'accès au membre dans une boucle, vous créez à chaque fois un nouvel objet et les performances s'en trouvent altérées. Si votre intention est de traiter le même objet dans chaque itération de boucle, il peut également s'agir d'une erreur de logique, car chaque accès de ce type crée un objet différent.
Éviter la requalification
Si vous faites de nombreuses références aux
membres d'un élément qualifié, telles que MyForm.Controls.Item(Subscript), vous pouvez
améliorer les performances en utilisant la construction
With ... End With :
With MyForm.Controls.Item(Subscript) ' Évaluer la qualification une seule fois.
.Name = "Numéro de contrôle " & CStr(Subscript)
.Text = .Name
' Accès aux autres membres de MyForm.Controls.Item(Subscript)
.Refresh()
End With
Le code précédent évalue une seule fois
MyForm.Controls.Item(Subscript). Son
exécution peut être deux fois plus rapide que lors
d'une requalification de chaque accès au membre.
Cependant, si l'élément n'est pas qualifié, par
exemple AnswerForm ou Me,
aucune amélioration de performances n'est à noter
avec With ... End With. Consultez l'article
With...End With Statements
pour
obtenir de plus amples informations.
Conversions du type
Deux types de classes présentent une relation d'héritage lorsque l'un dérive de l'autre. Si vous avez des objets de chacun de ces types et que vous devez en convertir un par rapport au type de l'autre, vous pouvez utiliser le mot clé DirectCast au lieu du mot clé CType. DirectCast peut parfois offrir de meilleures performances car il n'utilise pas les fonctions d'aide run-time. Notez que DirectCast renvoie une erreur InvalidCastException si aucune relation d'héritage n'existe entre les deux types. Consultez l'article DirectCast pour obtenir de plus amples informations.
Mise en cache de la propriété
Si vous accédez à une propriété à maintes reprises, par exemple dans une boucle itérative, vous pouvez améliorer les performances en mettant en cache la valeur de propriété. Pour ce faire, affectez la valeur de propriété à une variable avant d'entrer dans la boucle, puis utilisez cette variable à l'intérieur de la boucle. Le cas échéant, vous pouvez réaffecter la valeur de la variable sur la propriété en fin de boucle.
Si des accès à des propriétés utilisées de manière répétée représentent une partie considérable du code dans la boucle, leur mise en cache peut permettre à votre boucle de s'exécuter plus de trois fois plus rapidement.
Cependant, vous ne pourrez peut-être pas mettre en mémoire cache une propriété si ses méthodes Get et Set effectuent un traitement supplémentaire outre l'extraction ou le stockage de la valeur.
Traitement des exceptions
Traditionnellement, Visual Basic traite les erreurs à l'aide des instructions On Error GoTo et On Error Resume Next. Toutefois, ces instructions ne sont pas toujours d'une conception aisée et le code source qui en résulte est souvent compliqué et difficile à lire et à gérer.
Visual Basic .NET offre un traitement structuré des exceptions grâce aux instructions Try ... Catch ... Finally. Ce traitement est basé sur une structure de contrôle flexible et facile à lire. Le traitement structuré des exceptions peut contrôler un bloc de code donné pour plusieurs exceptions et gérer chacune d'elles différemment.
Ces deux approches permettent d'améliorer les performances. L'utilisation de l'instruction On Error Resume Next oblige le compilateur à générer un langage intermédiaire supplémentaire pour chaque instruction source dans le bloc à la suite de l'instruction On Error Resume Next. Un bloc Catch modifie l'état de l'objet Err au niveau de l'entrée et de la sortie. Les tests préliminaires indiquent que les performances de ces deux approches sont plus ou moins équivalentes lorsque le bloc contient moins de 20 instructions source. Cependant, les blocs comportant plusieurs centaines d'instructions s'exécutent plus facilement avec Try et Catch, car l'instruction On Error Resume Next génère davantage de langage intermédiaire pour un code source identique.
Si vous n'êtes pas obligé d'utiliser les
instructions On Error, optez pour le traitement
structuré des exceptions. Consultez l'article
Structured Exception Handling
pour
obtenir de plus amples informations.
Levée d'exceptions
Bien que le traitement structuré des exceptions soit utile, utilisez-le exclusivement pour les exceptions. Une exception n'est pas nécessairement une erreur, mais elle ne doit pas se produire trop fréquemment et dénote un fonctionnement anormal. La levée d'exceptions demande davantage de traitement que le test et le branchement, par exemple à l'aide d'une construction Select ou d'une boucle While. Les exceptions rendent également la lecture plus difficile lorsqu'elles sont utilisées pour le contrôle normal du flux. Ne les utilisez pas pour brancher ou renvoyer des valeurs.
Interception des exceptions
Les constructions Try ... Catch ... Finally provoquent peu de charges supplémentaires sur les performances, sauf en cas de levée d'exception. En d'autres termes, la création d'un gestionnaire d'exceptions n'altère en aucun cas les performances et vous ne devez pas hésiter à utiliser le traitement structuré des exceptions lorsque vous souhaitez éviter autant que possible qu'une exception ne se produise.
Strings
Les instances de la classe String sont immuables. Par conséquent, à chaque fois que vous modifiez une variable String, vous devez laisser tel quel l'objet String existant et en créer un nouveau. Si vous manipulez la même variable String à plusieurs reprises, cela peut avoir pour effet d'augmenter la taille de la mémoire et d'altérer les performances. Le traitement le plus courant est la concaténation, mais les méthodes String, telles que Insert et PadRight génèrent également de nouvelles instances.
StringBuilder
La classe StringBuilder dans l'espace de noms System.Text prend en charge une chaîne mutable qui conserve la même instance après modification. Pour l'utiliser, déclarez une variable de chaîne avec le type de données StringBuilder au lieu de String. Vous pouvez ensuite appeler ses méthodes Append, Insert, Remove et Replace pour manipuler la chaîne.
Si vous effectuez un grand nombre de concaténations ou d'autres modifications, la classe StringBuilder peut s'avérer jusqu'à trois fois plus rapide que le type de données String. Si vous le souhaitez, vous pouvez utiliser la méthode ToString pour copier les données de la chaîne finale vers un objet String une fois vos manipulations terminées.
Cependant, si vous n'envisagez aucune intervention
fréquente sur une même instance, il est
préférable d'utiliser String. En effet,
StringBuilder présente un inconvénient que la
classe String ne possède pas. Lors de la
création, le constructeur StringBuilder est plus
lent que le constructeur String. Pour conclure, dans la
plupart des cas, la méthode ToString est
conseillée. Consultez l'article
StringBuilder Class
pour
obtenir de plus amples informations.
Concaténation
Vous pouvez parfois combiner toutes les modifications de chaîne dans une seule instruction, par exemple :
MyString = PrefixString & ": " & MyString & " -- " & SuffixString
Une instruction de ce type crée seulement une nouvelle chaîne et ne provoque pas de liaison tardive car elle utilise l'opérateur &.
Lorsque vous concaténez des constantes de chaîne dans une instruction, Visual Basic les associe au moment de la compilation. Ceci génère la chaîne finale dans le langage intermédiaire, ce qui améliore les performances au moment de l'exécution. Notez que le résultat de la fonction ChrW peut être utilisé comme constante si son argument est constante.
Fonctions de la classe String
La fonction Format permet d'effectuer de nombreux contrôles, de nombreuses conversions de types, ainsi que d'autres traitements, y compris le formatage selon la langue définie. Si vous n'avez besoin d'aucune de ces fonctionnalités, utilisez la méthode ToString appropriée. Les méthodes ToString sont plus rapides que le mot clé de conversion CStr, car CStr procède à une analyse supplémentaire avant d'appeler ToString.
Les fonctions Asc et Chr utilisent les systèmes de codage SBCS (single-byte character set) et DBCS (double-byte character set). Elles doivent rechercher le thread actuel sur la page de codes, puis convertir les caractères vers et depuis le système Unicode. Les fonctions AscW et ChrW sont plus efficaces, car elles fonctionnent exclusivement dans Unicode et ne dépendent pas des options de langue et de la page de codes du thread en cours.
Procédures
Il existe un compromis entre appeler une procédure depuis une boucle et insérer le corps de la procédure directement dans la boucle. Si vous intégrez le code de la procédure dans la boucle, vous évitez de surcharger le mécanisme d'appel. Cependant, certaines parties de votre application ne pourront pas accéder à ce code. De même, si vous dupliquez le code à un autre emplacement, la maintenance devient plus difficile et vous risquez de provoquer des erreurs de synchronisation lors des mises à jour.
La définition de la procédure hors de la boucle facilite la lecture du code et rend accessible la procédure depuis d'autres emplacements de votre application. Le surplus d'appels est négligeable si la procédure est volumineuse. Cependant, il peut devenir assez conséquent si la procédure effectue uniquement une tâche réduite, comme accéder à un membre d'un objet de classe. Dans ce cas, il vaut mieux accéder directement au membre depuis la boucle en termes de performances.
Taille de la procédure
Les procédures sont soumises à la compilation juste-à-temps (JIT). Une procédure n'est compilée qu'après son premier appel. Le compilateur JIT tente d'effectuer plusieurs optimisations sur une procédure lors de sa compilation, telles que la génération du code en ligne pour les petits appels de procédure. Les procédures extrêmement volumineuses ne peuvent pas bénéficier de ces optimisations. Par exemple, il est peu probable qu'une procédure comportant plus de 1 000 lignes bénéficie d'une optimisation JIT.
Appel et retour
Dans les versions précédentes de Visual Basic, il était plus facile d'appeler une procédure à partir de son propre module qu'à partir d'un autre module, et plus rapide d'appeler une procédure à partir de son propre projet que d'un autre projet. Dans Visual Basic .NET, il n'existe aucune différence. L'emplacement d'une procédure par rapport au code d'appel n'est donc pas un critère de performances.
Utilisez l'instruction Return lorsque la logique le
permet. Consultez l'article
Return Statement
pour
obtenir de plus amples informations. Le compilateur permet une
meilleure optimisation du code qu'avec l'utilisation de Exit
Function, Exit Property ou Exit Sub, ou de
l'instruction End Function, End Get, End
Set ou End Sub pour générer un retour.
Appels virtuels
Un appel virtuel est un appel vers une procédure substituable. Notez que ceci dépend uniquement si la procédure a été déclarée à l'aide du mot clé Overridable et non si une substitution a été définie. Lorsque vous passez un appel virtuel, le common language runtime doit contrôler le type d'exécution de l'objet pour déterminer la substitution à appeler. En revanche, un appel non virtuel peut obtenir toutes les informations requises du type de compilation.
Du point de vue des performances, les appels virtuels prennent environ deux fois plus de temps que les appels non virtuels. Cette différence est particulièrement prononcée avec un type de valeur, par exemple lorsque vous appelez une procédure sur une structure. (Une structure ne peut pas déclarer des membres Overridable, mais elle hérite de Equals, GetHashCode et de ToString depuis Object et elle peut implémenter les membres Overridable des interfaces.) Définissez des procédures Overridable uniquement si vous souhaitez obtenir une structure claire et limitez le plus possible vos appels vers des procédures NotOverridable.
Arguments de procédure
Lorsque vous transférez un argument vers une procédure en utilisant le mot clé ByRef, Visual Basic copie uniquement un pointeur vers la variable sous-jacente, que cette variable soit un type de valeur ou un type de référence. Lorsque vous transférez un argument ByVal, le contenu de la variable sous-jacente est copié. Pour un type de référence, ce contenu comprend uniquement un pointeur vers l'objet lui-même. Cependant, pour un type de valeur, le contenu comprend toutes les données de la variable.
La différence de performances entre ByRef et ByVal est généralement insignifiante, en particulier pour les types de références. Pour les types de valeurs, la différence dépend de la largeur des données du type. La largeur des données de la plupart des types de valeur correspond généralement à la taille d'un pointeur. Dans ce cas, les performances sont équivalentes. Cependant, un type de valeur important, tel qu'une longue structure, peut être plus efficace que le transfert de ByRef pour éviter de copier toutes les données. D'autre part, lorsque vous transférez un type de valeur d'une taille optimale (Integer ou Double), il peut s'avérer préférable d'utiliser ByVal, car le compilateur peut fréquemment optimiser le code d'appel, par exemple en conservant l'argument dans un registre.
Étant donné que la différence de performances entre ByVal et ByRef n'est généralement pas importante, vous pouvez prendre en compte d'autres critères lorsque vous choisissez entre les deux mécanismes de transfert. L'avantage du transfert d'un argument ByRef réside dans le fait que la procédure peut renvoyer une valeur au code d'appel en modifiant le contenu de la variable transférée à l'argument. Pour ce qui est du transfert d'argument ByVal, cela empêche toute modification de variable par la procédure.
En l'absence de raison valable, il vaut toujours mieux opter
pour un transfert d'argument ByVal. Consultez l'article
Argument Passing ByVal and ByRef
pour
obtenir de plus amples informations.
Boucles
Réduisez le nombre de boucles dans un bloc Try et réduisez le nombre de blocs Try à l'intérieur d'une boucle. Une boucle longue peut augmenter la charge du traitement structuré des exceptions.
La question était ensuite de savoir laquelle des boucles For, Do ou While était la plus efficace. Le test préliminaire n'a révélé aucune différence notable. Par conséquent, les performances ne sont pas un élément déterminant dans le choix d'un type de boucle.
Collections
Lorsque vous parcourez une collection, vous pouvez utiliser une boucle For ou une boucle For Each. Si vous avez l'intention d'ajouter, de supprimer ou de réorganiser des éléments de la collection lors du parcours, une boucle For garantit davantage de résultats. Elle vous permet également de déterminer l'ordre du parcours. De plus, une collection dérivée de la classe CollectionBase dans l'espace de noms System.Collections lève une exception si vous tentez de modifier ses membres dans une boucle For Each.
Une boucle For Each donne le contrôle de la collection à l'objet énumérateur renvoyé par la méthode IEnumerable.GetEnumerator. Ceci signifie que vous ne pouvez pas nécessairement prévoir l'ordre du parcours. For Each est utile lorsque vous ne pouvez pas accéder aux membres d'une collection à l'aide de la propriété Item.
La différence en termes de performances entre les boucles For et For Each est négligeable.
Ajout de membres
Lorsque vous appelez la méthode Add d'une collection, évitez d'utiliser les arguments Before et After. Lorsque vous spécifiez un emplacement dans la collection avec Before ou After, vous obligez la collection à rechercher un membre avant qu'il n'ajoute votre nouveau membre.
Si vous utilisez une collection qui contient une méthode AddRange, utilisez-la de préférence sur Add. AddRange ajoute une liste entière ou une collection dans un appel. Plusieurs classes de collection exposent la méthode AddRange, par exemple la classe ArrayList dans l'espace de noms System.Collections et la classe ComboBox.ObjectCollection dans l'espace de noms System.Windows.Forms.
Threading
Si, dans votre application, les temps d'attente entre deux opérations sont assez longs, envisagez d'utiliser le traitement asynchrone, à l'aide des méthodes de la classe Thread dans l'espace de noms System.Threading. Ceci peut s'avérer utile lorsque vous attendez des réponses de l'utilisateur, ainsi que lorsque vous lisez et écrivez des données vers des supports physiques persistants. Le traitement asynchrone et le threading occasionnent du codage supplémentaire même si l'on peut constater une différence de performances considérable.
Assurez-vous, toutefois, que le threading supporte la surcharge et qu'il est utilisé correctement. Un thread avec une durée de vie courte est par nature inefficace et le changement de contexte prend beaucoup de temps. Utilisez un nombre minimum de threads à long terme et basculez entre eux le moins possible.
Mise en mémoire tampon multiple
Si votre application procède à des opérations de lecture et d'écriture importantes et que vous utilisez des E/S asynchrones, la mise en mémoire tampon multiple peut être avantageuse. Dans la mise en mémoire tampon multiple, vous affectez deux ou plusieurs mémoires tampon au fichier en lecture ou écriture. Alors que vous attendez la fin du traitement des E/S dans une mémoire tampon, vous pouvez procéder au traitement des données dans une autre mémoire tampon. La mise en mémoire tampon multiple est également appelée mise en mémoire tampon « swing ». Elle est communément appelée mise en mémoire tampon double lorsque vous utilisez deux mémoires tampon.
Appels interprocessus
Pour éviter toute surcharge du marshaling, il est
conseillé de réduire les appels interprocessus, les
appels distants et les appels vers les domaines d'application.
Ceci s'avère particulièrement vrai pour les appels
vers une frontière d'interopérabilité COM,
c'est-à-dire entre le code managé et le code non
managé (COM). Lorsque vous devez passez des appels
de ce type, essayez de les grouper plutôt que de les
disséminer. Un appel « groupé »
exécute plusieurs tâches, telles que l'initialisation
de tous les champs d'un objet. Un appel
« disséminé » exécute
uniquement une tâche courte. Consultez l'article
Programming with Application Domains and Assemblies
pour
obtenir de plus amples informations.
Types de données blittables
Les types de données blittables qui ont la même
représentation dans la mémoire managée et non
managée, peuvent être copiés dans la
frontière managée/non managée sans conversion.
Lorsque votre application passe des appels
d'interopérabilité COM, tentez d'utiliser uniquement
des types de données blittables pour les arguments. Les
types de données blittables dans Visual Basic .NET sont
Byte, Short, Integer, Long,
Single et Double. Les types du CLR
System.SByte, System.UInt16, System.UInt32
et System.UInt64 sont également blittables.
Consultez l'article
Blittable and Non-Blittable Types
pour
obtenir de plus amples informations.
Certains types de données composites peuvent également être blittables. Une structure composée d'un groupe de membres blittables est elle-même blittable. Une classe n'est pas automatiquement blittable même si tous ses membres le sont, mais vous pouvez tout de même améliorer les performances de marshaling en utilisant uniquement les membres blittables. Vous pouvez également définir le membre ExplicitLayout de l'énumération TypeAttributes dans l'espace de noms System.Reflection. Ceci force le marshaling des membres de classe au niveau des offsets spécifiés sans aucun réalignement par le CLR.
Marshaling
Le marshaling représente une partie importante des appels interprocessus et sa réduction peut améliorer les performances. Les types de données blittables et la structure du membre explicite sont extrêmement efficaces pour réduire la charge du marshaling. L'utilisation des structures au lieu de classes lorsque cela est possible améliore généralement les performances.
Le code managé peut également utiliser la fonction d'appel de la plate-forme pour appeler les fonctions non managées implémentées dans des DLL (bibliothèques de liaison dynamique), comme dans Win32 API. Pour utiliser l'appel de la plate-forme, déclarez chaque référence externe avec une instruction Declare, à l'aide des mots clés Function et Lib. L'appel des instructions Declare peut s'avérer plus efficace que l'appel d'objets COM. Consultez l'article Consuming Unmanaged DLL Functions pour obtenir de plus amples informations.
Optimisations supplémentaires
Compilation et précompilation
Votre code source est compilé en langage MSIL (Microsoft intermediate language) par le compilateur Visual Basic. Le MSIL réside dans le fichier .exe de votre application, qui est lu par le compilateur juste-à-temps (JIT) du CLR. Le compilateur JIT compile généralement le MSIL de chaque procédure en code natif de la plate-forme lors du premier appel de la procédure.
Il peut s'avérer utile de compiler les procédures fréquemment utilisées avant même de les appeler. L'environnement de développement intégré (IDE) exécute ce processus de précompilation pour les bibliothèques standard de Visual Basic et stocke les versions du code natif dans une section spécifique du global assembly cache (GAC). Vous économisez ainsi du temps en éliminant la compilation JIT pour les fonctions runtime Visual Basic.
Dans certains cas, des procédures spécifiques de votre application peuvent être parfaitement adaptées pour la précompilation. Par exemple, les applications Windows Forms utilisent généralement plusieurs bibliothèques partagées et appellent de nombreuses procédures lors du démarrage. Vous pouvez améliorer les performances si vous précompilez ces procédures.
Vous pouvez précompiler certaines parties de votre
application en utilisant ngen.exe lors
de l'installation. Notez que ngen.exe
n'appelle pas le compilateur JIT mais qu'il effectue sa propre
compilation. Consultez l'article
Native Image Generator (Ngen.exe)
pour
obtenir de plus amples informations. Lisez attentivement les
remarques suivantes avant de commencer la précompilation
de vos codes :
- Vous pouvez précompiler uniquement les applications côté client.
- Vous ne pouvez pas précompiler les applications ASP.NET.
- La précompilation est conçue pour améliorer les performances de votre application uniquement lors du démarrage.
- Les améliorations de performances ne sont pas nécessairement flagrantes. Lancez votre application avec et sans précompilation et comparez les minutages.
- La précompilation peut réduire
légèrement les performances d'exécution d'une
procédure fréquemment appelée. Ceci est
dû au fait que
ngen.exene peut pas effectuer certaines optimisations que le compilateur JIT effectue au moment de l'exécution.
DLL
Le chargement d'une bibliothèque de liaison dynamique (DLL) prend beaucoup de temps. L'utilisation d'une DLL pour appeler uniquement une ou deux procédures s'avère très inefficace. Il est conseillé de générer un nombre minimum de DLL, même si cela les rend plus volumineuses. Votre application doit donc utiliser le moins de projets possible et des solutions de grande envergure.
Version de débogage et version commerciale
Vous pouvez améliorer les performances en effectuant la compilation vers une version commerciale plutôt que vers une version de débogage. Les optimisations du compilateur sont alors disponibles, ce qui rend le langage intermédiaire plus petit et plus rapide. Cependant, ces optimisations réorganisent le code rendent le débogage plus difficile. Vous souhaitez peut-être compiler vers une version de débogage alors que votre application est encore en cours de développement.
Optimisation de la vitesse d'affichage
Dans une application Windows Forms, vous souhaitez parfois afficher des contrôles et des formulaires importants le plus rapidement possible. Pour optimiser la vitesse d'affichage, appliquez les remarques suivantes :
- Évitez de repeindre inutilement les contrôles. Il peut s'avérer utile de masquer les contrôles lorsque vous configurez leurs propriétés.
- Lorsque vous devez repeindre un contrôle ou un objet d'affichage, essayez de repeindre uniquement les dernières zones exposées d'un objet. Ceci réduit le temps d'attente de visualisation d'un affichage complet pour l'utilisateur.
- Il n'existe pas d'équivalent dans Visual Basic .NET pour le contrôle Image des versions précédentes. Vous devez utiliser les contrôles PictureBox pour afficher la plupart des graphiques. La fonction AutoRedraw n'est plus prise en charge. Consultez l'article Introduction to the Windows Forms PictureBox Control pour obtenir de plus amples informations.
Optimisation de la vitesse d'affichage perçue
Si vous ne souhaitez pas que l'utilisateur pense que votre application s'est arrêtée, vous pouvez tenter d'optimiser la vitesse d'affichage perçue. Les suggestions suivantes peuvent vous aider :
- Utilisez les indicateurs d'état d'avancement, tels
que le contrôle ProgressBar, disponible dans la
classe ProgressBar de l'espace de noms
System.Windows.Forms. Ceci permet de garantir à
l'utilisateur que votre application est toujours en cours
d'exécution. Consultez l'article
Introduction to the Windows Forms ProgressBar Control
pour obtenir de plus amples
informations. - Lors d'opérations de courte durée d'une seconde ou moins, vous pouvez transformer le pointeur de la souris en sablier, en utilisant la propriété MousePointer du contrôle Masked Edit.
- Préchargez les données essentielles avant qu'elles ne soient requises par votre application. Ces données comprennent des formulaires et des contrôles, ainsi que d'autres éléments de données. Bien que le chargement des ces éléments prenne encore beaucoup de temps, vous réduisez le temps d'attente de leur affichage à l'écran.
- Une fois que vous avez préchargé les formulaires ou les contrôles, maintenez-les masqués. Ceci réduit également le volume de peinture nécessaire.
- Pendant que votre application attend les entrées de l'utilisateur, utilisez les threads et les minuteurs pour effectuer des petites tâches en arrière-plan. Ceci peut vous aider à préparer les données pour l'affichage dès qu'elles sont demandées par l'utilisateur.
-
Il s'avère souvent utile d'optimiser la vitesse des
affichages précédents de votre application,
c'est-à-dire, ceux affichés lors du premier
chargement. Pour cela, respectez les consignes suivantes :
- Conservez vos formulaires et contrôles précédents le plus simplement possible pour réduire le temps de chargement et d'initialisation.
- Appelez
Me.Showcomme l'une des premières lignes de code dans chaque événement de chargement de formulaire. - Évitez de charger des modules qui ne sont pas requis immédiatement. Évitez d'appeler des procédures qui forcent ces chargements prématurés.
- Si votre affichage comprend une animation ou s'il modifie souvent un élément d'affichage, utilisez la mise en mémoire tampon double ou multiple pour préparer l'image suivante alors que l'image courante est en train d'être peinte. L'énumération ControlStyles dans l'espace de noms System.Windows.Forms s'applique à plusieurs contrôles et le membre DoubleBuffer peut empêcher le scintillement.
Réduction de la consommation de mémoire
Il est important de maintenir votre volume de code exécutable à un minimum. Vous devrez peut-être également réduire les exigences de mémoire des données de votre application. Ces réductions permettent généralement d'améliorer les performances, car les exécutables de taille réduite s'exécutent généralement plus rapidement. De plus, l'élimination des permutations de mémoire augmente la vitesse d'exécution. À cet égard, il peut s'avérer utile de tenir compte des recommandations suivantes :
- Limitez le nombre de formulaires chargés simultanément. Retardez le chargement d'un formulaire jusqu'à ce qu'il soit requis, sauf si vous souhaitez optimiser la vitesse d'affichage perçue. Lorsque vous avez fini de traiter un formulaire, déchargez-le et définissez la variable sur Nothing.
- Utilisez le moins de contrôles possible sur un formulaire. Utilisez les contrôles les plus petits et les plus simples qui exécutent ce dont vous avez besoin. Par exemple, utilisez des étiquettes au lieu de zones de texte.
- Conservez les procédures liées dans le même module. Ceci réduit le chargement des modules.
- Évitez d'utiliser des types de données trop importants, en particulier dans les tableaux.
- Une fois que vous avez terminé de traiter une variable d'un type de données important, définissez-la sur Nothing. Ceci s'applique surtout aux chaînes, aux tableaux et à d'autres objets potentiellement volumineux.
- Si vous avez terminé le traitement de certains éléments d'un tableau mais que vous devez conserver les autres, utilisez ReDim pour libérer de la mémoire inutilisée vers le garbage collection (GC).
Conclusions
Lorsque vous concevez et programmez une application Visual Basic .NET pour optimiser les performances, gardez à l'esprit ces points importants :
- Concentrez vos efforts d'optimisation sur le code qui s'exécute dans les boucles et les procédures fréquemment appelées.
- Recherchez les points les plus lents de votre application et optimisez-les pour atteindre des performances acceptables pour l'utilisateur.
- Utilisez des variables fortement typées et organisez-les pour une liaison anticipée sur les variables de l'objet, lorsque cela est possible.
- Définissez Option Strict On et Option Explicit On.
- Réduisez l'utilisation de la mémoire.
- Compilez vers une version commerciale lorsque vous n'avez pas besoin d'une version de débogage.
- Organisez votre application avec des solutions de grande envergure et le moins de projets possible.
- Évaluez vos performances, plutôt que de supposer tout simplement qu'une technique est plus efficace qu'une autre.
Le codage méthodique, ainsi qu'une conception correcte de la logique globale, constitue la première étape dans l'optimisation des performances. Le paramétrage n'est pas très utile si votre application n'est pas bien conçue dans sa totalité.
Autres ressources
Les ressources suivantes, qui font partie de la documentation Visual Studio .NET, fournissent des informations supplémentaires sur les concepts et les éléments de programmation abordés dans cet article.
Types de données
-
Value Types
- Décrit le concept des types de valeur dans .NET Framework.
-
Value Type Usage Guidelines
- Fournit les instructions générales de .NET Framework pour une utilisation correcte des types de valeur.
-
Data Types
- Définit le type de données et décrit les différents types disponibles dans Visual Basic .NET.
-
RemoveIntegerChecks Property
- Indique si les erreurs d'arithmétique sur les entiers entraînent des exceptions au moment de l'exécution.
-
Implicit and Explicit Conversions
- Décrit la conversion du type de données implicite et explicite et les mots clés de conversion.
-
ReDim Statement
- Réaffecte un espace de stockage pour une variable de tableau.
Déclarations
-
Option Compare Statement
- Déclare la méthode de comparaison à utiliser pour comparer les données de chaîne.
-
Collections in Visual Basic .NET
- Fournit une vue d'ensemble des collections qui traite de la classe Collection, des collections basées sur zéro et sur un, des valeurs clé et d'index et de la méthode d'ajout et de suppression des éléments.
-
Processing Drives, Folders, and Files
- Présente les trois principales façons d'accéder aux fichiers du disque avec Visual Basic .NET :
-
System.IO Namespace
- Contient des classes et d'autres types qui permettent la lecture et l'écriture synchrones et asynchrones sur des flux de données et des fichiers.
-
FileStream Class
- Présente le flux d'un fichier, prenant en charge les opérations de lecture et d'écriture synchrones et asynchrones.
-
BufferedStream Class
- Implémente la lecture et l'écriture mises en mémoire tampon sur un flux existant.
-
Multithreading in Visual Basic .NET
- Décrit comment exécuter plusieurs tâches simultanément.
Opérations
-
Boolean Expressions
- Traite des expressions qui évaluent les valeurs Boolean True ou False, les opérateurs de court-circuitage et les expressions placées entre parenthèses.
-
Logical Operators
- Fournit des informations sur les opérateurs qui comparent les expressions Boolean et renvoient un résultat Boolean.
-
ControlCollection Class
- Implémente un conteneur de collection qui permet aux contrôles du serveur ASP.NET de gérer une liste de leurs contrôles enfants.
-
Err Object
- Contient des informations sur les erreurs d'exécution.
-
Character Data Types
- Décrit les types Char et String.
-
Format Function
- Renvoie une chaîne formatée en fonction des instructions contenues dans une expression de type format.
-
Asc, AscW Functions
- Renvoie une valeur Integer représentant le code de caractère correspondant au caractère.
-
Chr, ChrW Functions
- Renvoie le caractère associé au code de caractère spécifié.
Procédures
-
For...Next Statements (Conceptual)
- Décrit le mode d'exécution d'un bloc d'instructions pour un nombre de fois spécifique.
-
For Each...Next Statements (Conceptual)
- Décrit le mode d'exécution d'un bloc d'instructions pour chaque élément d'une collection.
-
IEnumerable.GetEnumerator Method
- Renvoie un énumérateur pour un tableau pour permettre la lecture de ses données.
-
Add Method
- Ajoute un membre à un objet Collection Visual Basic .NET.
-
Item Property
- Renvoie un membre spécifique d'un objet Collection Visual Basic .NET par position ou par clé.
-
ComboBox.ObjectCollection Class
- Gère la collection des éléments dans ComboBox, y compris les chaînes, les images et les objets métiers personnalisés.
-
AppDomain Class
- Implémente un domaine d'application correspondant à un environnement isolé où s'exécutent les applications.
-
Thread Class
- Crée et contrôle un thread, définit sa priorité et obtient son statut.
-
System.Reflection Namespace
- Contient des classes et des interfaces qui fournissent une vue gérée des types chargés et de leurs membres, avec la possibilité de créer et d'appeler des types de manière dynamique.
-
TypeAttributes Enumeration
- Spécifie les attributs de type Visual Basic .NET qui correspondent à l'énumérateur CorTypeAttr comme défini dans le fichier corhdr.h.
-
Declare Statement
- Déclare les références aux procédures externes dans une bibliothèque de liaison dynamique (DLL).
Optimisations supplémentaires
-
Optimizations, Configuration Properties, <Projectname>
Property Pages Dialog Box
- Spécifie les paramétrages d'ensemble de votre projet. Ces paramétrages agissent par défaut, contrôlant l'aspect et le comportement des éléments tout au long du projet.
-
Property Pages Build Tab
- Permet de définir des options telles que Option Strict, ainsi que les contraintes personnalisées en place lorsque votre projet est initialisé.
-
Property Pages General Tab
- Permet d'accéder et de modifier le nom de votre projet, ainsi que l'espace de noms racine.
-
MousePointer Property (ActiveX Controls)
- Renvoie ou définit une valeur indiquant le type de pointeur de souris affiché lorsque la souris se trouve sur une partie spécifique d'un objet au moment de l'exécution.
-
ControlStyles Enumeration
- Spécifie le style et le comportement d'un contrôle.
-
Label Class (System.Web.UI.WebControls)
- Implémente un contrôle label, qui affiche du texte sur une page Web.
-
Label Class (System.Windows.Forms)
- Implémente une étiquette Windows standard, généralement utilisée pour fournir le texte descriptif d'un contrôle.
-
TextBox Class (System.Web.UI.WebControls)
- Crée une zone de texte qui permet à l'utilisateur de saisir du texte et définit ses propriétés.
-
TextBox Class (System.Windows.Forms)
- Représente le contrôle d'une zone de texte Windows qui permet à l'utilisateur de saisir du texte dans une application.
Articles sur les performances
-
Performance Considerations for Run-Time Technologies in the
.NET Framework
- Analyse les diverses technologies utilisées par les entreprises en environnement géré et explique comment elles influent sur les performances. Cette analyse couvre le garbage collection, le compilateur JIT, l'accès à distance, les types de valeur et la sécurité.
-
Performance Tips and Tricks in .NET Applications
- Décrit comment paramétrer correctement vos applications gérées pour optimiser vos performances. Inclut des exemples de code, des instructions de conception et des astuces de langage.
Dernière mise à jour le mercredi 11 décembre 2002