Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Klasa SpanOwner<T> jest typem buforu tylko dla stosu, który wynajmuje bufory z puli pamięci udostępnionej. Zasadniczo odzwierciedla funkcjonalność MemoryOwner<T>, ale jako typ ref struct. Ta funkcja jest szczególnie przydatna w przypadku buforów o krótkim czasie życia, które są używane tylko w kodzie synchronicznym (które nie wymagają Memory<T> wystąpień), jak również dla kodu działającego w ciasnej pętli. Tworzenie SpanOwner<T> wartości nie wymaga alokacji pamięci.
API platformy:
SpanOwner<T>,MemoryOwner<T>
Składnia
Te same podstawowe funkcje MemoryOwner<T> stosują się również do tego typu, z wyjątkiem tego, że jest to tylko stos struct. Nie ma również implementacji IMemoryOwner<T>interface ani właściwości Memory<T>. Składnia jest praktycznie identyczna ze składnią używaną z parametrem MemoryOwner<T>, z wyjątkiem różnic wymienionych wcześniej.
Załóżmy na przykład, że masz metodę, w której musisz przydzielić tymczasowy bufor o określonym rozmiarze (nazwijmy tę wartość length), a następnie użyjemy jej do wykonania pewnej pracy. Po pierwsze, nieefektywna wersja może wyglądać następująco:
byte[] buffer = new byte[length];
// Use buffer here
Ta wersja nie jest idealna, ponieważ przydziela nowy bufor za każdym razem, gdy używasz tego kodu, a następnie natychmiast go wyrzuca. Takie podejście wywiera większą presję na kolektor śmieci. Powyższy kod można zoptymalizować przy użyciu polecenia ArrayPool<T>:
// Using directive to access the ArrayPool<T> type
using System.Buffers;
int[] buffer = ArrayPool<int>.Shared.Rent(length);
try
{
// Slice the span, as it might be larger than the requested size
Span<int> span = buffer.AsSpan(0, length);
// Use the span here
}
finally
{
ArrayPool<int>.Shared.Return(buffer);
}
Powyższy kod wynajmuje bufor z puli tablic, ale jest bardziej obszerny i podatny na błędy. Należy zachować ostrożność w try/finally bloku, aby upewnić się, że zawsze zwracasz wynajęty bufor do basenu. Możesz go ponownie napisać przy użyciu SpanOwner<T> typu , w następujący sposób:
// Be sure to include this using at the top of the file:
using Microsoft.Toolkit.HighPerformance.Buffers;
using SpanOwner<int> buffer = SpanOwner<int>.Allocate(length);
Span<int> span = buffer.Span;
// Use the span here, no slicing necessary
Wystąpienie SpanOwner<T> wewnętrznie wynajmuje tablicę i dba o zwracanie jej do puli, gdy wykracza poza zakres. Nie trzeba już używać try/finally bloku, ponieważ kompilator języka C# dodaje to automatycznie podczas rozszerzania tej using instrukcji. W związku z tym, możesz postrzegać SpanOwner<T> typ jako lekką otoczkę wokół interfejsów ArrayPool<T> API. Sprawia to, że są one zarówno bardziej kompaktowe, jak i łatwiejsze do użycia, zmniejszając ilość kodu potrzebnego do pisania w celu prawidłowego wynajmu i usuwania buforów krótkotrwałych. Możesz zobaczyć, jak użycie SpanOwner<T> sprawia, że kod jest znacznie krótszy i prostszy.
Uwaga
Jako że jest to typ wyłącznie stosowy, opiera się na wzorcu opartym na typizacji duck wprowadzonym w C# 8. Ten schemat jest wyświetlany w poprzednim przykładzie: typ SpanOwner<T> jest używany w bloku using pomimo faktu, że typ w ogóle nie implementuje interfejsu IDisposable i nigdy nie jest pakowany. Funkcjonalność jest taka sama: gdy tylko bufor wykracza poza zakres, jest on automatycznie usuwany. API w SpanOwner<T> polegają na tym wzorcu dla zwiększenia wydajności: zakładają, że podstawowy bufor nigdy nie jest usuwany, o ile typ SpanOwner<T> znajduje się w zasięgu. Nie wykonują dodatkowych kontroli, które są wykonywane w MemoryOwner<T>, aby upewnić się, że bufor jest nadal dostępny przed zwróceniem wystąpienia Memory<T> lub Span<T> z niego. W związku z tym zawsze używaj tego konkretnego typu z blokiem lub wyrażeniem using. Nie powoduje to zwrócenia bazowego buforu do puli udostępnionej. Technicznie można osiągnąć ten sam wynik, ręcznie wywołując Dispose na typie SpanOwner<T> (co nie wymaga języka C# 8), ale takie podejście jest podatne na błędy i dlatego nie jest zalecane.
Przykłady
.NET Community Toolkit