Maison >développement back-end >Tutoriel C#.Net >Code d'implémentation sur la façon d'utiliser ref et Span pour améliorer les performances du programme dans .Net Core

Code d'implémentation sur la façon d'utiliser ref et Span pour améliorer les performances du programme dans .Net Core

黄舟
黄舟original
2017-05-21 11:11:443554parcourir

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. Les amis dans le besoin peuvent s'y référer

1. Préface

En fait, en ce qui concerne la ref, de nombreux étudiants le savent déjà. ref est une fonctionnalité du langage

C# 7.0, qui est utilisé pour le développement Personnel fournit des mécanismes pour renvoyer des variables références locales et des références de valeur. 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 car le

langage C est identique aux pointeurs d'exploitation. Une telle syntaxe de haut niveau entraîne toujours des effets secondaires, mais je ne pense pas que ce soit quoi que ce soit, et tous les développeurs C# n'ont pas besoin d'en avoir une compréhension approfondie. les mécanismes de fonctionnement internes. Je pense que, quelle que soit la complexité des choses, cela ne donne qu'un libre choix aux gens. Le risque et la flexibilité sont toujours incompatibles.

Regardons quelques exemples pour illustrer la similitude entre les références et les 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 ci-dessus

. La fonction utilise respectivement des pointeurs ref et non safe pour compléter le paramètre +1.

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érençant les variables locales)

int i = 42;
ref var x = ref i;
x = x + 1;
// i = 43
Dans cet exemple C'est une référence x à la variable locale i. Lorsque la valeur de x est modifiée, la valeur de la variable i change également.

2.ref returns (référence de valeur de retour)

ref return est une fonctionnalité puissante en C# 7. Le code suivant est le plus efficace Reflétant ses caractéristiques, cette fonction fournit une référence à un élément du tableau

renvoyée par int :

public static ref int GetArrayRef(int[] items, int index) => ref items[index];
obtient la référence à l'élément du tableau via l'indice, et lorsque en changeant la valeur de référence, le tableau changera également en conséquence.

3. Span

System.Span fait partie du noyau .Net Core, dans System.Memory.

dl l Sous l'assemblage. Cette fonctionnalité est actuellement indépendante et pourra être intégrée à CoreFx dans le futur

Comment l'utiliser ? Le package NuGet suivant est référencé dans 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 les opérations de type pointeur (T*) fournies par le mot-clé ref sur une seule valeur

objet Chemin. Fondamentalement, l'exploitation de pointeurs n'est pas considérée comme un bon événement sous le système .NET. Bien sûr, .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 que ce sera une abstraction du pointeur d'opération (void*) dans .NET. Les développeurs familiers avec C/C++ devraient mieux savoir 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 à 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 entier) :

S'il y a une

chaînechaîne<a href="http://www.php.cn/wiki/57.html" target="_blank">string</a> content = "content-length:123", content = "content -length: 123",Pour convertir 123 en entier, l'approche habituelle consiste d'abord à Substrpour 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'un scénario typique d'utilisation d'une sous-chaîne. Chaque fois qu'une chaîne est utilisée, un nouvel objet chaîne est généré. utilisé à plusieurs reprises lors de l'exécution de int.Parse. Si un grand nombre d'opérations sont effectuées, cela exercera une 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");

这里将string转换为int的算法利用ReadonlySpan实现,这也是Span的典型使用场景,官方给的场景也是如些,Span适用于多次复用操作连续内存的场景。

转换代码如下:

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(&#39;-&#39;)){
   sign = -1; index = 1;
  }
  for (int idx = index; idx < rspan.Length; idx++){
   char c = rspan[idx];
   num = (c - &#39;0&#39;) + num * 10;
  }
  return num * sign;
 }
}

四、最后

上述两段代码100000次调用的时间如下:

String Substring Convert:
  Time Elapsed: 18ms
ReadOnlySpan Convert:
  Time Elapsed: 4ms

目前Span的相关支持还够,它只是最基础架构,之后CoreFx会对很多API使用Span进行重构和实现。可见.Net Core的性能日后会越来越强大。

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn