SpanOwner<T>
SpanOwner<T>
è un tipo di buffer solo stack che noleggia i buffer da un pool di memoria condivisa. Rispecchia essenzialmente la funzionalità di MemoryOwner<T>
, ma come ref struct
tipo . Ciò è particolarmente utile per i buffer di breve durata usati solo nel codice sincrono (che non richiedono Memory<T>
istanze), nonché per il codice in esecuzione in un ciclo stretto, perché la creazione SpanOwner<T>
di valori non richiederà affatto allocazioni di memoria.
API della piattaforma:
SpanOwner<T>
,MemoryOwner<T>
Sintassi
Le stesse funzionalità di base di MemoryOwner<T>
si applicano anche a questo tipo, ad eccezione del fatto che si tratta di un solo stack struct
e del fatto che manca l'implementazione IMemoryOwner<T>
interface
, nonché la Memory<T>
proprietà . La sintassi è praticamente identica a quella usata anche con MemoryOwner<T>
, ad eccezione delle differenze indicate in precedenza.
Si supponga, ad esempio, di avere un metodo in cui è necessario allocare un buffer temporaneo di una dimensione specificata (chiamiamo questo valore length
) e quindi usarlo per eseguire alcune operazioni. Una prima versione inefficiente potrebbe essere simile alla seguente:
byte[] buffer = new byte[length];
// Use buffer here
Questo non è l'ideale, poiché allocare un nuovo buffer ogni volta che viene usato questo codice e quindi eliminarlo immediatamente (come indicato anche nella MemoryOwner<T>
documentazione), che mette più pressione sul Garbage Collector. È possibile ottimizzare il codice precedente usando 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);
}
Il codice precedente noleggia un buffer da un pool di matrici, ma è più dettagliato e soggetto a errori: è necessario prestare attenzione al try/finally
blocco per assicurarsi di restituire sempre il buffer affittato al pool. È possibile riscriverlo usando il SpanOwner<T>
tipo , come illustrato di seguito:
// 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
L'istanza SpanOwner<T>
noleggierà internamente una matrice e si occuperà di restituirla al pool quando esce dall'ambito. Non è più necessario usare un try/finally
blocco, perché il compilatore C# lo aggiungerà automaticamente durante l'espansione di tale using
istruzione. Di conseguenza, il SpanOwner<T>
tipo può essere visto come un wrapper leggero intorno alle ArrayPool<T>
API, che li rende sia più compatta che più facile da usare, riducendo la quantità di codice che deve essere scritta correttamente per noleggiare ed eliminare buffer di breve durata. È possibile vedere come l'uso SpanOwner<T>
di rende il codice molto più breve e più semplice.
Nota
Poiché si tratta di un tipo solo stack, si basa sul modello tipizzato IDisposable
anatra introdotto con C# 8. Come illustrato nell'esempio precedente: il SpanOwner<T>
tipo viene usato all'interno di un using
blocco nonostante il fatto che il tipo non implementa affatto l'interfaccia IDisposable
e non viene mai sottoposto a boxing. La funzionalità è identica: non appena il buffer esce dall'ambito, viene eliminato automaticamente. Le API in SpanOwner{T}
si basano su questo modello per ottenere prestazioni aggiuntive: presuppongono che il buffer sottostante non venga mai eliminato finché il SpanOwner<T>
tipo è nell'ambito e non eseguono i controlli aggiuntivi eseguiti per MemoryOwner<T>
assicurarsi che il buffer sia effettivamente disponibile prima di restituire un'istanza Memory<T>
o Span<T>
da essa. Di conseguenza, questo tipo deve essere sempre usato con un blocco o un'espressione using
. In caso contrario, il buffer sottostante non verrà restituito al pool condiviso. Tecnicamente lo stesso può essere ottenuto anche chiamando Dispose
manualmente sul SpanOwner<T>
tipo (che non richiede C# 8), ma che è soggetto a errori e quindi non consigliato.
Esempi
Altri esempi sono disponibili negli unit test.
.NET Community Toolkit