80 votes

Quelle est la différence entre Span<T> et Memory<T> en C# 7.2 ?

C# 7.2 introduit deux nouveaux types : Span<T> y Memory<T> qui offrent de meilleures performances par rapport aux types C# antérieurs comme string[] .

Question : Quelle est la différence entre Span<T> y Memory<T> ? Pourquoi utiliser l'un plutôt que l'autre ?

4 votes

2 votes

@JeffMercado Y a-t-il une liste complète quelque part des types C# qu'ils peuvent remplacer en plus de string[] ? Sont-ils seulement pour les tableaux ou peuvent-ils aussi être utilisés à la place de types comme List<T> ?

71voto

Coding Points 2867

Span<T> n'est qu'une pile par nature, tandis que Memory<T> peuvent exister sur le tas.

Span<T> est un nouveau type que nous ajoutons à la plateforme pour représenter pour représenter des régions contiguës de mémoire arbitraire, avec des de performances comparables à celles de T[]. Ses API sont similaires à celles des tableaux, mais contrairement aux tableaux, il peut pointer vers de la mémoire gérée ou native, ou encore vers de la mémoire allouée sur la pile.

Memory <T> est un type qui complète Span<T> . Comme indiqué dans son document de conception document, Span<T> est un type de pile uniquement. La nature de la pile de Span<T> le rend inadapté à de nombreux scénarios qui nécessitent de stocker des des références à des tampons (représentés par Span<T> ) sur le tas, par exemple pour les routines routines effectuant des appels asynchrones.

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;
}

Pour résoudre ce problème, nous fournirons un ensemble de types complémentaires, destinés à être utilisés comme des types d'échange d'usage général représentant, tout comme Span <T> , une gamme de mémoire arbitraire, mais contrairement à Span <T> ces types ne seront pas uniquement des piles, au prix de pénalités de performance performances pour la lecture et l'écriture dans la mémoire.

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;
}

Dans l'exemple ci-dessus, le Memory <byte> est utilisé pour représenter le tampon. Il s'agit d'un type régulier et peut être utilisé dans des méthodes faisant des appels asynchrones. Sa propriété Span renvoie Span<byte> mais la valeur retournée n'est pas stockée sur le tas pendant les appels asynchrones, mais plutôt de nouvelles valeurs sont produites à partir du Memory<T> valeur. Dans un sens, Memory<T> est une usine de Span<T> .

Document de référence : aquí

10 votes

Que signifie "nature de la pile" ?

5 votes

Je suis un novice. La pile ne serait-elle pas ramenée à l'endroit où elle se trouvait avant l'attente ? Je n'ai pas compris pourquoi le tampon ne peut pas survivre à la continuation dans la fonction Span<byte> buffer exemple. Pourquoi perdons-nous l'adresse du point de la mémoire où pointe le tampon[0] ?

3 votes

@Spectraljump Si je ne me trompe pas, toute variable dans une méthode async sera, en réalité, un champ de classe une fois compilé (donc, sur le tas), afin de pouvoir utiliser ces valeurs après un await. Si le Span ne peut être que sur la pile, ce ne serait pas le même Span avant et après le await.

43voto

Krzysztof Cwalina Points 279

Re : cela signifie qu'il ne peut pointer que sur la mémoire allouée sur la pile.

Span<T> peut pointer vers n'importe quelle mémoire : allouée soit sur la pile, soit sur le tas. La nature de la pile uniquement de Span<T> signifie que le Span<T> lui-même (et non la mémoire vers laquelle il pointe) doit résider uniquement sur la pile. Ceci est en contraste avec les structs C# "normaux", qui peuvent résider sur la pile ou sur le tas (soit par le biais d'un boxing de type valeur, soit lorsqu'ils sont intégrés dans des classes/types de référence). Certaines des implications pratiques les plus évidentes sont que vous ne pouvez pas avoir un objet Span<T> dans une classe, vous ne pouvez pas encadrer Span<T> et vous ne pouvez pas en faire un tableau.

0 votes

Ah, encore un de ces types qui ressemblent à des sous-préfets.

1 votes

Mais pourquoi ne peut-elle résider que sur Stack ? Et pourquoi ne pouvez-vous pas les mettre en boîte ? ou ne pouvez pas les mettre en classe ?

4 votes

Si vous pouviez obtenir un Span<T> n'importe où sur le tas (via boxing, membre d'une classe...), alors vous auriez un objet sur un tas qui pourrait pointer vers la mémoire sur la pile, qui serait libérée quand, disons, une fonction est revenue. Vous auriez alors un objet sur le tas qui pointerait vers la mémoire libérée, ce qui pourrait conduire à un défaut de segmentation.

-7voto

Olivier Duhart Points 34

Memory<T> peut être considéré comme une version non sécurisée mais plus polyvalente de Span<T> . Accès à un Memory<T> échouera s'il pointe vers un tableau libéré.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X