
Microsoft .NET est le nom donné à un ensemble de produits et de technologies informatiques de l'entreprise Microsoft pour rendre des applications facilement portables sur Internet. .NET 6 RC1 a été testé et est pris en charge par la Preview 4 de Visual Studio 2022. Dans la version 6 de .NET, les diagnostics du cloud ont été améliorés avec dotnet monitor et OpenTelemetry. La prise en charge de WebAssembly est plus performante. De nouvelles API ont été ajoutées, pour HTTP/3, le traitement de JSON, les mathématiques et la manipulation directe de la mémoire.
Voici, ci-dessous, quelques-unes des améliorations apportées à .NET 6 :
Une plateforme unifiée et étendue
.NET 6 offre une plateforme unifiée, pour les applications web, cloud, de bureau, d'IoT et mobiles. La plateforme sous-jacente a été mise à jour pour répondre aux besoins de tous les types d'applications et pour faciliter la réutilisation du code dans toutes les applications. Les nouvelles capacités et améliorations sont disponibles pour toutes les applications en même temps, de sorte qu’un code exécuté dans le cloud ou sur un appareil mobile se comporte de la même manière et bénéficie des mêmes avantages.
La portée des développeurs .NET continue de s'élargir à chaque version. L'apprentissage automatique et WebAssembly sont deux des ajouts les plus récents. Par exemple, avec l'apprentissage automatique, il est possible d’écrire des applications qui recherchent des anomalies dans les données en continu. Avec WebAssembly, il est possible d’héberger des applications .NET dans le navigateur, tout comme HTML et JavaScript, ou les combiner avec HTML et JavaScript.
L'un des ajouts les plus intéressants est l'interface utilisateur multiplateforme de .NET (.NET MAUI). Il est désormais possible d’écrire du code dans un seul projet qui offre une expérience d'application client moderne sur les systèmes d'exploitation mobiles et de bureau. .NET MAUI sera publié un peu plus tard que .NET 6.
Contrôle et casting plus rapides d'interface
Les performances de casting d'interface ont été améliorées de 16 % à 38 %. Cette amélioration est particulièrement utile pour la correspondance de modèle de C# vers et entre les interfaces. Le graphique ci-dessous illustre l'ampleur de l'amélioration pour un benchmark représentatif.
L'un des principaux avantages du passage de certaines parties du moteur d'exécution de .NET de C++ à C# géré est qu'il réduit la barrière à la contribution. Cela inclut le casting d'interface, qui a été déplacé vers C# lors d'un changement précoce de .NET 6. Beaucoup plus de personnes dans l'écosystème .NET maîtrisent le C# que le C++ (et le runtime utilise des modèles C++ difficiles). Le simple fait de pouvoir lire une partie du code qui compose le moteur d'exécution est une étape importante pour développer la confiance dans la contribution sous ses différentes formes.
Arm64
L’équipe de développement de .NET a ajouté le support initial pour Arm64 avec .NET Core 3.0 et Arm32 avant cela. L'équipe a fait des investissements majeurs dans Arm64 dans chacune des dernières versions. Dans .NET 6, elle s’est principalement concentrée sur la prise en charge des nouvelles puces Apple Silicon et du scénario d'émulation x64 sur les systèmes d'exploitation macOS et Windows Arm64.
« L'Arm64 suscite beaucoup d'enthousiasme en ce moment, que ce soit pour les ordinateurs portables, le matériel informatique et d'autres appareils. Nous ressentons cette même excitation au sein de l'équipe .NET et faisons de notre mieux pour suivre cette tendance industrielle. Nous collaborons directement avec les ingénieurs d'Arm Holdings, d'Apple et de Microsoft pour nous assurer que nos implémentations sont correctes et optimisées, et que nos plans s'alignent. Ces partenariats étroits nous ont beaucoup aidés », souligne Richard Lander.
Il est possible d’installer les versions Arm64 et x64 de .NET sur les systèmes d'exploitation macOS 11+ et Windows 11+ Arm64. Pour parvenir à ce résultat, l’équipe de développement de .NET a dû faire plusieurs choix de conception et modifier ses produits pour que cela fonctionne. Par défaut, si une application .NET 6 est exécutée avec le SDK Arm64, elle s'exécutera en Arm64. Il est possible de passer facilement à l'exécution en x64 avec l'argument -a, comme dotnet run -a x64. Le même argument fonctionne pour les autres CLI.
Lorsque -a x64 est utilisé, le SDK s'exécute toujours de manière native en Arm64. Il existe des points fixes dans l'architecture du SDK .NET où les limites de processus existent. La plupart du temps, un processus doit être tout Arm64 ou tout x64. En réalité, le .NET CLI attend la dernière création de processus dans l'architecture du SDK et lance celui-ci comme l'architecture de puce qui a été demandée, comme x64. C'est dans ce processus que le code s'exécute. De cette façon, le développeur bénéficie des avantages de l'Arm64 en tant que développeur, mais le code s'exécute dans le processus dont il a besoin. Ceci n'est pertinent que s’il a besoin d'exécuter du code en x64. Si ce n'est pas le cas, il est tout simplement possible de tout exécuter en Arm64 tout le temps.
Windows Arm64
Microsoft dispose d'un outil simple qui démontre l'environnement sur lequel tourne .NET.
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | C:Usersrich>dotnet tool install -g dotnet-runtimeinfo You can invoke the tool using the following command: dotnet-runtimeinfo Tool 'dotnet-runtimeinfo' (version '1.0.5') was successfully installed. C:Usersrich>dotnet runtimeinfo 42 42 ,d ,d 42 42 42 ,adPPYb,42 ,adPPYba, MM42MMM 8b,dPPYba, ,adPPYba, MM42MMM a8" `Y42 a8" "8a 42 42P' `"8a a8P_____42 42 8b 42 8b d8 42 42 42 8PP""""""" 42 "8a, ,d42 "8a, ,a8" 42, 42 42 "8b, ,aa 42, `"8bbdP"Y8 `"YbbdP"' "Y428 42 42 `"Ybbd8"' "Y428 **.NET information Version: 6.0.0 FrameworkDescription: .NET 6.0.0-rtm.21522.10 Libraries version: 6.0.0-rtm.21522.10 Libraries hash: 4822e3c3aa77eb82b2fb33c9321f923cf11ddde6 **Environment information ProcessorCount: 8 OSArchitecture: Arm64 OSDescription: Microsoft Windows 10.0.22494 OSVersion: Microsoft Windows NT 10.0.22494.0 |
L'outil fonctionne en mode natif sur Windows Arm64. Voici, ci-dessous, le résultat en ASP.NET Core.
Performances de l'Arm64
Les projets de prise en charge d'Apple Silicon et de l'émulation x64 étaient très importants, mais les performances de l'Arm64 ont également été améliorées. L’image ci-dessous montre une amélioration de la mise à zéro du contenu des cadres de pile, qui est une opération courante. La ligne verte représente le nouveau comportement, tandis que la ligne orange représente une autre expérience (moins avantageuse), toutes deux améliorées par rapport à la ligne de base, représentée par la ligne bleue. Pour ce test, plus bas est mieux.
PGO dynamique
Le Dynamic Profile-guided Optimization (PGO) ou encore l'optimisation dynamique guidée par le profil peut améliorer sensiblement les performances en régime permanent. Par exemple, PGO permet une amélioration de 26 % (510K -> 640K) des requêtes par seconde pour la suite TechEmpower JSON "MVC". PGO dynamique s'appuie sur la compilation par niveaux, qui permet aux méthodes d'être d'abord compilées très rapidement (niveau 0) pour améliorer les performances au démarrage, puis d'être recompilées (niveau 1) avec de nombreuses optimisations une fois que la méthode s'est révélée efficace. Ce modèle permet d'instrumenter les méthodes au niveau 0 afin d'effectuer diverses observations sur l'exécution du code.
Lorsque ces méthodes sont réintroduites au niveau 1, les informations recueillies à partir des exécutions du niveau 0 sont utilisées pour mieux optimiser le code du niveau 1. C'est l'essence même du mécanisme. Les temps de démarrage de Dynamic PGO seront légèrement plus lents que ceux du runtime par défaut, car du code supplémentaire est exécuté dans les méthodes de niveau 0 pour observer le comportement de la méthode.
Pour activer PGO dynamique, il faut definir DOTNET_TieredPGO=1 dans l'environnement où l’application sera exécutée. Il faut également s’assurer que Tiered Compilation est activé (il l'est par défaut). Dynamic PGO est opt-in parce qu'il s'agit d'une technologie nouvelle et importante. Le PGO dynamique est pris en charge et est déjà utilisé en production par au moins un très grand service Microsoft.
Code : | Sélectionner tout |
1 2 3 4 | private IEnumerator<long> _source = Enumerable.Range(0, long.MaxValue).GetEnumerator(); [Benchmark] public void MoveNext() => _source.MoveNext(); |
Voici le résultat, avec et sans PGO dynamique :
C'est une différence assez importante, mais la taille du code a également augmenté, ce qui pourrait en surprendre plus d'un. Il s'agit de la taille du code d'assemblage généré par le JIT, et non des allocations de mémoire. Une optimisation courante dans les implémentations PGO est le « fractionnement chaud/froid », où les sections d'une méthode fréquemment exécutées ("chaudes"


Comme contexte, la répartition d'interface est le type d'appel le plus coûteux dans .NET. Les appels de méthodes non virtuelles sont les plus rapides, et encore plus rapides sont les appels qui peuvent être éliminés par inlining. Dans ce cas, le PGO dynamique fournit deux sites d'appel (alternatifs) pour MoveNext. Le premier, le chaud, est un appel direct à Enumerable+RangeIterator.MoveNext et l'autre, le froid, est un appel à l'interface virtuelle via IEnumerator<int>. C'est une grande victoire si le chaud est appelé la plupart du temps.
Lorsque le JIT a instrumenté le code de niveau 0 pour cette méthode, il a notamment instrumenté cette répartition d'interface pour suivre le type concret de _source à chaque invocation. Et le JIT a trouvé que chaque invocation était sur un type appelé Enumerable+RangeIterator, qui est une classe privée utilisée pour implémenter Enumerable.Range à l'intérieur de l'implémentation Enumerable. En tant que tel, pour le niveau 1, le JIT a émis une vérification pour voir si le type de _source est ce Enumerable+RangeIterator : si ce n'est pas le cas, alors il saute à la section froide que a été précédemment mise en évidence qui effectue la répartition normale de l'interface. Mais si c'est le cas, ce qui, d'après les données de profilage, devrait être le cas dans la grande majorité du temps, il peut alors invoquer directement la méthode Enumerable+RangeIterator.MoveNext, non virtualisée. De plus, il a décidé qu'il était rentable de mettre en ligne cette méthode MoveNext. L'effet net est que le code assembleur généré est un peu plus gros, mais optimisé pour le scénario exact qui devrait être le plus courant.
Améliorations des entrées-sorties de fichiers
FileStream a été presque entièrement réécrit dans .NET 6, en mettant l'accent sur l'amélioration des performances des entrées-sorties de fichiers asynchrones. Sous Windows, l'implémentation n'utilise plus d'API bloquantes et peut être jusqu'à plusieurs fois plus rapide. Microsoft a également apporté des améliorations à l'utilisation de la mémoire, sur toutes les plateformes. Après la première opération asynchrone (qui alloue généralement la mémoire), l’équipe de développement de .NET a fait en sorte que les opérations asynchrones ne nécessitent aucune allocation. De plus, elle a uniformisé le comportement pour les cas limites où les implémentations Windows et Unix étaient différentes. Les améliorations de performance de cette réécriture profitent à tous les systèmes d'exploitation. Les utilisateurs de macOS et de Linux devraient également constater une amélioration significative des performances de FileStream. Le benchmark suivant écrit 100 Mo dans un nouveau fichier.
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | private byte[] _bytes = new byte[8_000]; [Benchmark] public async Task Write100MBAsync() { using FileStream fs = new("file.txt", FileMode.Create, FileAccess.Write, FileShare.None, 1, FileOptions.Asynchronous); for (int i = 0; i < 100_000_000 / 8_000; i++) await fs.WriteAsync(_bytes); } |
Sous Windows avec un disque SSD, une accélération de 4 fois et une diminution de l'allocation de plus de 1200 a été observée :
L’équipe de développement de .NET a également reconnu le besoin de fonctionnalités d'E/S de fichiers plus performantes : lectures et écritures simultanées, et E/S de type scatter/gather. Elle a introduit de nouvelles API dans les classes System.IO.File et System.IO.RandomAccess pour ces cas.
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 | async Task AllOrNothingAsync(string path, IReadOnlyList<ReadOnlyMemory<byte>> buffers) { using SafeFileHandle handle = File.OpenHandle( path, FileMode.Create, FileAccess.Write, FileShare.None, FileOptions.Asynchronous, preallocationSize: buffers.Sum(buffer => buffer.Length)); // hint for the OS to pre-allocate disk space await RandomAccess.WriteAsync(handle, buffers, fileOffset: 0); // on Linux it's translated to a single sys-call! } |
L'exemple présente :
- l'ouverture d'un handle de fichier à l'aide de la nouvelle API File.OpenHandle ;
- pré-affectation de l'espace disque à l'aide de la nouvelle fonctionnalité Taille de pré-affectation ;
- écriture dans le fichier à l'aide de la nouvelle API Scatter/Gather IO.
La fonctionnalité Size de préallocation améliore les performances car les opérations d'écriture n'ont pas besoin d'étendre le fichier et il est moins probable que le fichier soit fragmenté. Cette approche améliore la fiabilité puisque les opérations d'écriture n'échoueront plus en raison d'un manque d'espace puisque l'espace a déjà été réservé. L'API Scatter/Gather IO réduit le nombre d'appels système requis pour écrire les données.
Sécurité
La sécurité a été considérablement améliorée dans .NET 6. Elle constitue toujours une priorité pour l'équipe, y compris la modélisation des menaces, la cryptographie et les mesures de défense en profondeur. Sous Linux, l’équipe de développement de .NET s’appuie sur OpenSSL pour toutes les opérations cryptographiques, y compris pour TLS (requis pour HTTPS). Sous macOS et Windows, elle s’appuie sur les fonctionnalités fournies par le système d'exploitation dans le même but. Avec chaque nouvelle version de .NET, elle doit souvent ajouter la prise en charge d'une nouvelle version d'OpenSSL. .NET 6 ajoute la prise en charge d'OpenSSL 3.
OpenSSL a annoncéle 21 septembre la disponibilité de la version 3.0 et le renouvellement de la Licence Apache-2.0, avec l'utilisation du nouveau module FIPS dans les projets de développement d'applications. « Après 3 ans de développement, 17 versions alpha, 2 versions bêta, plus de 7 500 commits et des contributions de plus de 350 auteurs différents, nous avons finalement publié OpenSSL 3.0 ! », a annoncé Matt Caswell sur le blog officiel dédié à la plateforme.
.NET 6 requiert OpenSSL 1.1 ou plus et préférera la plus haute version installée d'OpenSSL qu'il peut trouver, jusqu'à et y compris la v3. Dans le cas général, l’utilisation d’OpenSSL 3 commencera probablement lorsque la distribution Linux utilisée l'adoptera par défaut. La plupart des distributions ne l'ont pas encore fait. Par exemple, l’installation de .NET 6 sur Red Hat 8 ou Ubuntu 20.04, ne permet pas (au moment de la rédaction de cette news ) d’utiliser OpenSSL 3.
L’équipe de développement de .NET a...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.