.NET 4.6 apporte certaines fonctionnalités CLR liées à l'amélioration des performances. Certaines de ces fonctionnalités prendront effet automatiquement, tandis que d'autres, telles que SIMD et Async Local Storage, nécessitent des modifications dans la façon dont les applications sont écrites.
L'équipe Mono a toujours été fière de prendre en charge SIMD, la fonctionnalité de flux de données multiples à flux d'instruction unique. SIMD est un jeu d'instructions CPU capable d'effectuer la même opération sur jusqu'à 8 valeurs en même temps. Avec le lancement de .NET CLR version 4.6, les développeurs Windows peuvent enfin utiliser cette fonctionnalité.
Afin d'observer réellement l'effet du SIMD, vous pouvez vous référer à cet exemple. Supposons que vous deviez ajouter deux tableaux sous la forme c[i] = a[i] b[i] pour obtenir un troisième tableau. En utilisant SIMD, vous pouvez écrire du code de la manière suivante :
for (int i = 0; i < size; i += Vector.Count) { Vectorv = new Vector(A,i) + new Vector(B,i); v.CopyTo(C,i); }
Notez comment cette boucle s'incrémente de la valeur de Vector
Cette méthode semble un peu lourde, c'est pourquoi Microsoft propose également une série de classes auxiliaires, notamment :
Structure Matrice3x2
Structure Matrix4x4
Structure plane
Structure quaternion
Classe de vecteur
Structure du vecteur (T)
Structure Vecteur2
Structure Vector3
Structure Vector4
Je crains que la plupart des développeurs ne le sachent pas : .NET charge souvent deux fois le même assembly. La condition pour que cela se produise est que .NET charge d'abord la version IL d'un assembly, puis charge la version NGEN (c'est-à-dire la version précompilée) du même assembly. Cette approche constitue un sérieux gaspillage de mémoire physique, en particulier pour les grandes applications 32 bits telles que Visual Studio.
Dans .NET 4.6, une fois que le CLR charge la version NGEN d'un assembly, il effacera automatiquement la mémoire occupée par la version IL correspondante.
Plus tôt, nous avons discuté du mode de latence du garbage collection introduit dans .NET 4.0. Bien que cette méthode soit beaucoup plus fiable que de laisser le GC s'arrêter complètement pendant un certain temps, elle n'est toujours pas suffisante pour terminer de nombreux scénarios de GC.
Dans .NET 4.6, vous pourrez suspendre temporairement le garbage collector de manière plus sophistiquée. La nouvelle méthode TryStartNoGCRegion vous permet de spécifier la quantité de mémoire nécessaire dans le tas pour les petits objets et les gros objets.
Si la mémoire est insuffisante, le moteur d'exécution renvoie false ou s'arrête jusqu'à ce que suffisamment de mémoire soit obtenue via le nettoyage du GC. Vous pouvez contrôler ce comportement en transmettant un indicateur à TryStartNoGCRegion. Si vous entrez avec succès dans une zone sans GC (le GC n'est pas autorisé avant la fin du processus), la méthode EndNoGCRegion doit être appelée à la fin du processus.
La documentation officielle n'indique pas si cette méthode est thread-safe, mais compte tenu du principe de fonctionnement de GC, vous devriez essayer d'éviter que deux processus tentent de modifier l'état du GC en même temps.
Une autre amélioration apportée au GC réside dans la façon dont il gère les objets épinglés (c'est-à-dire les objets qui ne peuvent pas être déplacés une fois alloués). Bien que cet aspect soit décrit de manière quelque peu vague dans la documentation, lorsque vous fixez la position d'un objet, cela corrige généralement également la position des objets adjacents. Rich Lander a écrit dans l'article :
Le GC gérera les objets épinglés de manière plus optimisée, afin qu'il puisse compresser plus efficacement la mémoire autour des objets épinglés. Pour les applications à grande échelle utilisant un grand nombre de broches, ce changement améliorera considérablement les performances de l'application.
GC fait également preuve d'une meilleure intelligence dans la façon d'utiliser la mémoire dans les générations précédentes. Rich a continué à écrire :
.La façon dont les objets de génération 1 sont promus en objets de génération 2 a également été améliorée pour utiliser la mémoire plus efficacement. Avant d'allouer un nouvel espace mémoire pour une génération, le GC essaiera d'abord d'utiliser l'espace disponible. Dans le même temps, un nouvel algorithme est utilisé lors de la création d'objets en utilisant l'espace disponible, de sorte que la taille de l'espace nouvellement alloué soit plus proche de la taille de l'objet qu'auparavant.
La dernière amélioration n'est pas directement liée aux performances, mais elle permet toujours d'obtenir des résultats d'optimisation grâce à une utilisation efficace. Avant que les API asynchrones ne deviennent populaires, les développeurs pouvaient exploiter le stockage local par thread (TLS) pour mettre en cache les informations. TLS agit comme un objet global pour un thread spécifique, ce qui signifie que vous pouvez accéder directement aux informations contextuelles et les mettre en cache sans avoir à transmettre explicitement un objet contextuel.
En mode asynchrone/attente, le stockage local des threads devient inutile. Parce que chaque fois que wait est appelé, il est possible de passer à un autre thread. Et même si vous parvenez à éviter cette situation, d'autres codes peuvent accéder à votre fil de discussion et interférer avec les informations contenues dans TLS.
La nouvelle version de .NET introduit le mécanisme de stockage local asynchrone (ALS) pour résoudre ce problème. ALS est sémantiquement équivalent au stockage local de thread, mais il peut effectuer les sauts correspondants avec l'appel de wait. Cette fonction sera implémentée via la classe générique AsyncLocal, qui appellera en interne l'objet CallContext pour sauvegarder les données.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!