Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Jedná se SpanOwner<T> o typ vyrovnávací paměti jen pro zásobník, který pronajímá vyrovnávací paměti ze sdíleného fondu paměti. V podstatě zrcadlí funkčnost MemoryOwner<T>, ale jako ref struct typ. To je zvlášť 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é kód spuštěný v těsné smyčce, protože vytváření SpanOwner<T> hodnot vůbec nevyžaduje přidělení paměti.
Rozhraní API platformy:
SpanOwner<T>,MemoryOwner<T>
Syntaxe
Stejné základní funkce MemoryOwner<T> platí i pro tento typ, s výjimkou, že je pouze structzásobník , a skutečnost, že chybí IMemoryOwner<T>interface implementace, stejně jako Memory<T> vlastnost. Syntaxe je prakticky identická s tím MemoryOwner<T> , s výjimkou výše uvedených rozdílů.
Předpokládejme například, že máme metodu, kdy potřebujeme 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
To není ideální, protože při každém použití tohoto kódu přidělujeme novou vyrovnávací paměť a okamžitě ji zahodíme (jak je uvedeno také v MemoryOwner<T> dokumentaci), což klade větší tlak na uvolňování paměti. Výše uvedený kód můžeme 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);
}
Výše uvedený kód pronajímá vyrovnávací paměť z fondu polí, ale je náchylnější a náchylnější k chybám: musíme být opatrní s try/finally blokem, abychom vždy vrátili zapůjčení vyrovnávací paměti do fondu. Můžeme ho SpanOwner<T> přepsat pomocí typu, 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, jakmile bude mimo rozsah. Už nemusíme používat try/finally blok, protože kompilátor jazyka C# přidá tento blok automaticky při rozbalení daného using příkazu. Jako takový SpanOwner<T> lze typ považovat za jednoduchý obálka kolem ArrayPool<T> rozhraní API, což zkomprimuje a usnadňuje jejich použití, což snižuje množství kódu, který je potřeba zapsat k řádnému pronájmu a odstranění krátkodobých vyrovnávacích pamětí. 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. To je znázorněno v ukázce výše: SpanOwner<T> typ se používá v using bloku navzdory tomu, že typ vůbec neimplementuje IDisposable rozhraní a není nikdy boxován. Funkce je stejná: jakmile vyrovnávací paměť zmizí z rozsahu, automaticky se odstraní. Rozhraní API SpanOwner<T> spoléhají na tento vzor pro zvýšení výkonu: předpokládají, že základní vyrovnávací paměť nebude nikdy uvolněna, pokud SpanOwner<T> je typ v oboru, a neprovádějí další kontroly, které jsou provedeny MemoryOwner<T> , aby se zajistilo, že vyrovnávací paměť je ve skutečnosti stále k dispozici před vrácením Memory<T> instance nebo Span<T> z ní. Tento typ by měl být vždy použit s blokem nebo výrazem using . Tím se nevrátí základní vyrovnávací paměť do sdíleného fondu. Technicky totéž lze dosáhnout také ručním voláním Dispose typu SpanOwner<T> (který nevyžaduje C# 8), ale to je náchylné k chybám, a proto se nedoporučuje.
Příklady
.NET Community Toolkit