コード分​​析: ref と Span を使用して .Net Core でプログラムのパフォーマンスを向上させる

巴扎黑
リリース: 2017-08-14 11:53:12
オリジナル
1684 人が閲覧しました

この記事では、.Net Core で ref と Span を使用してプログラムのパフォーマンスを向上させる簡単な実装コードを主に紹介します。必要な方は参考にしてください。 ref については、多くの学生がすでに知っています。ref は、開発者にローカル変数参照と値参照を返すメカニズムを提供する C# 7.0 の言語機能です。

Span も ref 構文に基づく複雑なデータ型です。記事の後半では、その使用方法を示す例を示します。

2. Ref キーワード


ref キーにしろ out キーにしろ、C 言語でのポインタの操作と同様に、このような高度な構文は常に何らかの副作用を伴いますが、理解と操作が難しい言語機能です。私はこれが大したことではないと思いますし、すべての C# 開発者がこれらの内部動作メカニズムを深く理解する必要があるわけではありません。複雑さは関係なく、人々に自由な選択肢を提供するだけであり、リスクと柔軟性は決して両立しないと思います。 。

参照とポインターの類似性を説明するために、いくつかの例を見てみましょう。 もちろん、次の使用方法は C# 7.0 より前でも使用できます。

public static void IncrementByRef(ref int x)
{
 x++;
}
public unsafe static void IncrementByPointer(int* x)
{
 (*x)++;
}
ログイン後にコピー

上記の 2 つの関数は、それぞれ ref と unsafe ポインターを使用します。パラメータ +1 を完成させます。


int i = 30;
IncrementByRef(ref i);
// i = 31
unsafe{
 IncrementByPointer(&i);
}
// i = 32
ログイン後にコピー

C# 7.0 で提供される機能は次のとおりです:


1.ref ローカル (ローカル変数の参照)


int i = 42;
ref var x = ref i;
x = x + 1;
// i = 43
ログイン後にコピー

この例では、ローカル i の参照 x です。変数、x を変更すると、i 変数の値も変更されます。
2.ref returns (戻り値参照)


ref returns は、C# 7 の強力な機能です。次のコードは、その機能を最もよく反映しています:

public static ref int GetArrayRef(int[] items, int index) => ref items[index];
ログイン後にコピー
添字を介して配列内の項目の参照を取得します。参照値が変更されると、それに応じて配列も変更されます。


3. Span


System.Span は、System.Memory.dll アセンブリの下にある .Net Core コアの一部です。現在、この機能は独立していますが、将来 CoreFx に統合される可能性があります

使用方法?次の NuGet パッケージは、.Net Core 2.0 SDK によって作成されたプロジェクトの下で参照されます:

 <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>
ログイン後にコピー

上記では、ref キーワードを使用して提供できる単一値オブジェクトを操作するポインター (T*) のような方法を見てきました。 。基本的に、.NET システムではポインターの操作は良いこととは考えられていません。もちろん、.NET は単一値の参照を安全に操作するための ref を提供します。しかし、単一の値は、「ポインター」を使用するユーザーのニーズのほんの一部にすぎません。ポインターの場合、より一般的な状況は、連続したメモリ空間で一連の「要素」を操作する場合です。

スパンは、既知の長さとタイプの連続したメモリ ブロックとして表されます。メモリ領域ポインタへの安全なアクセスを提供するという点で、多くの点で T[] または ArraySegment と非常に似ています。実際、これが .NET の操作 (void*) ポインターの抽象化になることは、C/C++ に詳しい開発者であればよく理解できるはずです。


スパン機能は次のとおりです:

•配列、アンマネージ ポインタ、スタック ポインタ、固定または固定された管理データ、および値の内部領域への参照を含む、すべての連続メモリ空間の型システムを抽象化します

• CLR 標準のオブジェクト型と値型をサポートします

•ジェネリクスをサポートします •独自に管理および解放する必要があるポインターとは異なり、GC をサポートします 構文的にも意味的にも ref: に関連する Span の定義を見てみましょう。


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 {...} }
 ...
}
ログイン後にコピー

次に、直感的な例を使用して Span の使用シナリオを説明します。例として、文字のインターセプトと文字の変換 (整数への変換) を取り上げます。整数型の場合、通常のアプローチは、最初に部分文字列を使用して、数値と関係のない文字列を切り捨てることです。 変換コードは次のとおりです。 . Substring に限らず、文字列の操作ごとに新しい文字列オブジェクトが生成されます。大量の操作が実行されると、GC に負荷がかかります。

このアルゴリズムを実装するには Span を使用します。


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");
ログイン後にコピー

文字列を int に変換するアルゴリズムは、Span の典型的な使用シナリオでもあります。公式のシナリオも同様です。連続メモリの再利用シナリオ。 conversonコンバージョンコードは次のとおりです:

string content = "content-length:123",

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");
ログイン後にコピー
e44。最後に


上記の2つのコードの100000個の呼び出しの時間は次のとおりです。これは最も基本的なアーキテクチャにすぎません。その後、CoreFx は Span を使用して多くの API を再構築し、実装します。 .Net Core のパフォーマンスは今後ますます強力になることがわかります。

以上がコード分​​析: ref と Span を使用して .Net Core でプログラムのパフォーマンスを向上させるの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート