Maison >développement back-end >Tutoriel C#.Net >Analyse de code : utilisation de ref et Span
Cet article présente principalement le code d'implémentation simple de l'utilisation de ref et Span8742468051c85b06f0a0af9e3e506b5c dans .Net Core pour améliorer les performances du programme.
1.
En fait, en ce qui concerne ref, de nombreux étudiants le savent déjà. Ref est une fonctionnalité du langage C# 7.0. Elle fournit aux développeurs un mécanisme pour renvoyer des références de variables locales et des références de valeurs. .
Span est également un type de données complexe basé sur la syntaxe ref. Dans la seconde moitié de l'article, j'aurai un exemple montrant comment l'utiliser.
2. Mot-clé de référence
Qu'il s'agisse de clé de référence ou de sortie, c'est une fonctionnalité de langage difficile à comprendre et à utiliser, telle Comme pour le fonctionnement des pointeurs en langage C, une telle syntaxe de haut niveau entraîne toujours des effets secondaires, mais je ne pense pas que cela ait quoi que ce soit, et je pense que tous les développeurs C# ne doivent pas avoir une compréhension approfondie de ces mécanismes de fonctionnement internes. Ce qui est compliqué, c'est qu'il ne donne qu'un libre choix aux gens. Le risque et la flexibilité ne sont jamais compatibles.
Regardons quelques exemples pour illustrer l'identité des références et des pointeurs. Bien entendu, les méthodes d'utilisation suivantes peuvent être utilisées avant C# 7.0 :
public static void IncrementByRef(ref int x) { x++; } public unsafe static void IncrementByPointer(int* x) { (*x)++; }
Les deux fonctions ci-dessus utilisent ref et unsafe pointer pour compléter le paramètre +1 respectivement.
int i = 30; IncrementByRef(ref i); // i = 31 unsafe{ IncrementByPointer(&i); } // i = 32
Voici les fonctionnalités fournies par C# 7.0 :
1.ref locals (référencement de variables locales)
int i = 42; ref var x = ref i; x = x + 1; // i = 43
Dans cet exemple, il s'agit de la référence x de la variable locale i. Lorsque la valeur de x est modifiée, la valeur de la. Je variable change également.
2.ref return (référence de valeur de retour)
ref return est une fonctionnalité puissante en C# 7. Le code suivant reflète le mieux ses fonctionnalités. Cette fonction fournie, renvoie. une référence à un élément du tableau int :
public static ref int GetArrayRef(int[] items, int index) => ref items[index];
Obtenez la référence à l'élément du tableau via l'indice. Lors de la modification de la valeur de référence, Le tableau changera également en conséquence.
3. Span
System.Span fait partie du noyau .Net Core, sous l'assembly System.Memory.dll. Cette fonctionnalité est actuellement indépendante et pourra être intégrée à CoreFx dans le futur
Comment l'utiliser ? Référencez le package NuGet suivant sous le projet créé par le SDK .Net Core 2.0 :
<ItemGroup> <PackageReference Include="System.Memory" Version="4.4.0-preview1-25305-02" /> <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0-preview1-25305-02" /> </ItemGroup>
Ci-dessus, nous avons vu des pointeurs similaires (T*) qui peuvent être fournis en utilisant la référence mot-clé ) méthode d’exploitation d’objets à valeur unique. Fondamentalement, l'exploitation de pointeurs n'est pas considérée comme une bonne chose dans le système .NET. Bien entendu, .NET nous fournit des références pour exploiter en toute sécurité des références à valeur unique. Mais une seule valeur ne représente qu'une petite partie des besoins de l'utilisateur en matière d'utilisation de « pointeurs » ; pour les pointeurs, la situation la plus courante est celle de l'utilisation d'une série d'« éléments » dans un espace mémoire continu.
Span est représenté comme un bloc de mémoire contigu de longueur et de type connus. À bien des égards, il est très similaire à T[] ou ArraySegment dans le sens où il fournit un accès sécurisé aux pointeurs de régions mémoire. En fait, je comprends qu'il s'agira d'une abstraction du pointeur d'opération (void*) dans .NET. Les développeurs familiers avec C/C++ devraient mieux comprendre ce que cela signifie.
Les caractéristiques de Span sont les suivantes :
• Extrait le système de types de tous les espaces mémoire continus, y compris : les tableaux, les pointeurs non gérés, pointeurs de pile, données gérées fixes ou épinglées et références à des zones de valeurs internes
•Prend en charge les types d'objets et les types de valeurs standard CLR
•Prend en charge les génériques
•Prend en charge GC, contrairement aux pointeurs qui doivent être gérés par eux-mêmes
Jetons un coup d'œil à la définition de Span, qui est grammaticalement et sémantiquement liée à la ref :
public struct Span<T> { ref T _reference; int _length; public ref T this[int index] { get {...} } ... } public struct ReadOnlySpan<T> { ref T _reference; int _length; public T this[int index] { get {...} } ... }
Ensuite, j'utiliserai. un exemple intuitif pour illustrer le scénario d'utilisation de Span ; prenons comme exemple l'interception de caractères et la conversion de caractères (conversion en type entier) :
S'il y a une chaîne string content = "content-length:123",
à convertir, convertissez 123 en type entier, généralement La méthode consiste à utiliser d'abord Substring pour tronquer la chaîne qui n'a rien à voir avec des caractères numériques. Le code de conversion est le suivant :
string content = "content-length:123"; Stopwatch watch1 = new Stopwatch(); watch1.Start(); for (int j = 0; j < 100000; j++) { int.Parse(content.Substring(15)); } watch1.Stop(); Console.WriteLine("\tTime Elapsed:\t" + watch1.ElapsedMilliseconds.ToString("N0") + "ms");
Pourquoi. Utiliser cet exemple ? Il s'agit d'une sous-chaîne typique. Scénarios d'utilisation : Chaque fois qu'une chaîne est manipulée, un nouvel objet chaîne est généré. Bien sûr, ce n'est pas seulement une sous-chaîne qui est manipulée à plusieurs reprises. un grand nombre d'opérations sont effectuées, cela fera pression sur le GC.
Utilisez Span pour implémenter cet algorithme :
string content = "content-length:123"; ReadOnlySpan<char> span = content.ToCharArray(); span.Slice(15).ParseToInt(); watch.Start(); for (int j = 0; j < 100000; j++) { int icb = span.Slice(15).ParseToInt(); } watch.Stop(); Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
L'algorithme de conversion de chaîne en int est implémenté à l'aide de ReadonlySpan. Il s'agit également d'un scénario d'utilisation typique. de Span. Les scénarios officiels sont les mêmes. Span convient aux scénarios dans lesquels la mémoire continue est réutilisée plusieurs fois.
Le code de conversion est le suivant :
public static class ReadonlySpanxtension { public static int ParseToInt(this ReadOnlySpan<char> rspan) { Int16 sign = 1; int num = 0; UInt16 index = 0; if (rspan[0].Equals('-')){ sign = -1; index = 1; } for (int idx = index; idx < rspan.Length; idx++){ char c = rspan[idx]; num = (c - '0') + num * 10; } return num * sign; } }
Enfin
Ci-dessus Le temps pour 100 000 appels vers les deux morceaux de code est le suivant :
String Substring Convert: Time Elapsed: 18ms ReadOnlySpan Convert: Time Elapsed: 4ms
Actuellement, le support associé pour Span est suffisant. l'architecture la plus basique. À l'avenir, CoreFx utilisera Span pour de nombreuses API Refactor et implémentera. On peut voir que les performances de .Net Core deviendront de plus en plus puissantes à l'avenir.
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!