třída SpanOwner<T>

Třída SpanOwner<T> je typ vyrovnávací paměti určený pouze pro zásobník, který půjčuje vyrovnávací paměti ze sdíleného fondu paměti. V podstatě zrcadlí funkčnost MemoryOwner<T>, ale v podobě typu ref struct. Tato funkce je obzvláště užitečná pro krátkodobé vyrovnávací paměti, které se používají pouze v synchronním kódu (které nevyžadují Memory<T> instance), a také pro kód spuštěný v těsné smyčce. Vytváření SpanOwner<T> hodnot nevyžaduje přidělení paměti.

Rozhraní API platformy:SpanOwner<T>, MemoryOwner<T>

Syntaxe

Stejné základní funkce MemoryOwner<T> se vztahují i na tento typ, s výjimkou toho, že jde o zásobník pouze pro použití ve stacku struct. Chybí také IMemoryOwner<T>interface implementace, stejně jako Memory<T> vlastnost. Syntaxe je prakticky identická se syntaxí použitou MemoryOwner<T>s výjimkou rozdílů uvedených výše.

Předpokládejme například, že máte metodu, ve které potřebujete přidělit dočasnou vyrovnávací paměť zadané velikosti (pojďme tuto hodnotu lengthvolat) a pak ji použít k provedení nějaké práce. První neefektivní verze může vypadat takto:

byte[] buffer = new byte[length];

// Use buffer here

Tato verze není ideální, protože při každém použití tohoto kódu přidělí novou vyrovnávací paměť a okamžitě ji zahodí. Tento přístup klade větší tlak na uklízeč paměti. Předchozí kód můžete optimalizovat pomocí 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);
}

Předchozí kód pronajímá vyrovnávací paměť z fondu polí, ale je to podrobnější a náchylnější k chybám. Musíte být opatrní s blokem try/finally, abyste měli jistotu, že vždy vrátíte zapůjčený vyrovnávací paměti do bazénu. Typ SpanOwner<T> můžete použít k přepsání, například takto:

// 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

Instance SpanOwner<T> interně pronajímá pole a postará se o jeho vrácení do fondu, když přejde mimo rozsah. Už nemusíte používat try/finally blok, protože kompilátor jazyka C# přidá tento blok automaticky při rozbalení daného using příkazu. V tomto smyslu můžete typ SpanOwner<T> chápat jako odlehčenou obálku kolem rozhraní API ArrayPool<T>. Díky tomu jsou kompaktnější a snadněji použitelné, což snižuje množství kódu, který je třeba napsat, aby bylo možné správně pronajímat a likvidovat dočasné vyrovnávací paměti. Uvidíte, jak použití SpanOwner<T> kódu výrazně zkracuje a zjednodušuje.

Poznámka:

Vzhledem k tomu, že se jedná o typ jen pro zásobník, spoléhá na vzor typu kachního typu zavedený IDisposable v jazyce C# 8. Tento vzor je uvedený v předchozím vzorku: SpanOwner<T> Typ se používá v using bloku, i když typ vůbec neimplementuje IDisposable rozhraní, a také se nikdy nezablokuje. Funkce je stejná: jakmile vyrovnávací paměť zmizí z rozsahu, automaticky se odstraní. Rozhraní API SpanOwner<T> spoléhají na tento vzor ke zvýšení výkonu: předpokládají, že základní vyrovnávací paměť není nikdy uvolněna, dokud je typ SpanOwner<T> v oboru. Neprovádějí další kontroly, které se provádí v MemoryOwner<T>, aby se zajistilo, že vyrovnávací paměť je stále k dispozici před vrácením instance Memory<T> nebo instance Span<T> z ní. Proto tento typ vždy používejte s blokem nebo výrazem using . Pokud se tak neučiní, základní vyrovnávací paměť se nevrátí do sdíleného fondu. Technicky vzato můžete dosáhnout stejného výsledku ručním voláním Dispose typu SpanOwner<T> (který nevyžaduje C# 8), ale tento přístup je náchylný k chybám, a proto se nedoporučuje.

Příklady

Další příklady najdete v jednotkových testech.