Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
La SpanOwner<T> classe è un tipo di buffer a sola pila che ottiene i buffer da un pool di memoria condiviso. Rispecchia essenzialmente la funzionalità di MemoryOwner<T>, ma come tipo ref struct. Questa funzionalità è particolarmente utile per i buffer di breve durata usati solo nel codice sincrono (che non richiedono Memory<T> istanze), nonché il codice in esecuzione in un ciclo stretto. La creazione di SpanOwner<T> valori non richiede 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 oggetto solo stack struct. Manca anche l'implementazione IMemoryOwner<T>interface , nonché la Memory<T> proprietà . La sintassi è praticamente identica alla sintassi usata 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 (chiamare 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
Questa versione non è ideale perché alloca un nuovo buffer ogni volta che si usa questo codice e quindi lo elimina immediatamente. Questo approccio comporta una maggiore 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 noleggiato al pool. È possibile riscriverlo usando il SpanOwner<T> tipo , ad esempio:
// 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> noleggia internamente una matrice e si occupa della restituzione al pool quando esce dall'ambito. Non è più necessario usare un try/finally blocco, perché il compilatore C# lo aggiunge automaticamente quando si espande tale using istruzione. Di conseguenza, è possibile visualizzare il SpanOwner<T> tipo come wrapper leggero intorno alle ArrayPool<T> API. Li rende sia più compatti che più facili da usare, riducendo la quantità di codice che è necessario scrivere per noleggiare correttamente 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 di duck typing introdotto con C# 8. Questo modello è illustrato nell'esempio precedente: il tipo SpanOwner<T> viene utilizzato all'interno di un blocco using nonostante il fatto che il tipo non implementi affatto l'interfaccia IDisposable e non sia mai effettuato il 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. Non eseguono i controlli aggiuntivi eseguiti in MemoryOwner<T> per assicurarsi che il buffer sia ancora disponibile prima di restituire un'istanza Memory<T> o Span<T> da essa. Di conseguenza, usare sempre questo tipo con un blocco o un'espressione using . In caso contrario, il buffer sottostante non viene restituito al pool condiviso. Tecnicamente, è possibile ottenere lo stesso risultato chiamando Dispose manualmente sul SpanOwner<T> tipo (che non richiede C# 8), ma questo approccio è soggetto a errori e quindi non consigliato.
Esempi
Altri esempi sono disponibili negli unit test.
.NET Community Toolkit