web-dev-qa-db-ja.com

C#7.2のSpan <T>とMemory <T>の違いは何ですか?

C#7.2には、Span<T>Memory<T>の2つの新しい型が導入されており、string[]などの以前のC#型よりもパフォーマンスが向上しています。

質問:Span<T>Memory<T>の違いは何ですか?なぜ私は一方をもう一方の上に使用するのですか?

51
Dan Sorensen

Span<T>は本質的にスタック専用ですが、Memory<T>はヒープ上に存在できます。

Span<T>は、T []と同等のパフォーマンス特性を持つ、任意のメモリの連続領域を表すためにプラットフォームに追加する新しいタイプです。そのAPIは配列に似ていますが、配列とは異なり、マネージメモリまたはネイティブメモリ、またはスタックに割り当てられたメモリを指すことができます。

Memory <T>は、Span<T>を補完する型です。設計ドキュメントで説明したように、Span<T>はスタックのみのタイプです。 Span<T>のスタックのみの性質により、バッファへの参照(Span<T>で表される)をヒープに格納する必要がある多くのシナリオに適していません。非同期呼び出しを行うルーチン用。

async Task DoSomethingAsync(Span<byte> buffer) {
    buffer[0] = 0;
    await Something(); // Oops! The stack unwinds here, but the buffer below
                       // cannot survive the continuation.
    buffer[0] = 1;
}

この問題に対処するために、Span <T>と同様に、任意のメモリの範囲を表す汎用交換タイプとして使用することを目的とした補完タイプのセットを提供しますが、Span <T>とは異なり、これらのタイプはスタックのみで、メモリの読み取りと書き込みのパフォーマンスが大幅に低下します。

async Task DoSomethingAsync(Memory<byte> buffer) {
    buffer.Span[0] = 0;
    await Something(); // The stack unwinds here, but it's OK as Memory<T> is
                       // just like any other type.
    buffer.Span[0] = 1;
}

上記のサンプルでは、​​Memory <byte>を使用してバッファーを表します。これは通常のタイプであり、非同期呼び出しを行うメソッドで使用できます。そのSpanプロパティはSpan<byte>を返しますが、戻り値は非同期呼び出し中にヒープに格納されませんが、Memory<T>値から新しい値が生成されます。ある意味では、Memory<T>Span<T>のファクトリです。

参照ドキュメント: here

49
Hussein Salman

re:これは、スタックに割り当てられたメモリのみをポイントできることを意味します。

Span<T>は、スタックまたはヒープに割り当てられた任意のメモリを指すことができます。 Span<T>のスタックのみの性質は、Span<T>自体(ポイントするメモリではない)がスタック上にのみ存在する必要があることを意味します。これは「通常の」C#構造体とは対照的です。C#構造体は、スタックまたはヒープに常駐できます(値型のボクシング、またはクラス/参照型に埋め込まれている場合)。より明白な実際的な意味合いのいくつかは、クラスにSpan<T>フィールドを含めることができず、Span<T>をボックス化できず、それらの配列を作成できないことです。

27