Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
A SpanOwner<T> classe é um tipo de buffer apenas de pilha que aluga buffers de um pool de memória partilhado. Ele essencialmente espelha a funcionalidade do MemoryOwner<T>, mas como um ref struct tipo. Esta funcionalidade é particularmente útil para buffers de vida curta que são usados apenas em código síncrono (que não requerem instâncias Memory<T>), bem como para código executado num ciclo apertado. Criar SpanOwner<T> valores não requer alocações de memória.
APIs da plataforma :
SpanOwner<T>,MemoryOwner<T>
Sintaxe
As mesmas funcionalidades principais de MemoryOwner<T> aplicam-se a este tipo também, com a exceção de ser apenas um struct de pilha. Também lhe falta a IMemoryOwner<T>interface implementação, bem como a Memory<T> propriedade. A sintaxe é praticamente idêntica à usada com MemoryOwner<T>, exceto pelas diferenças mencionadas anteriormente.
Por exemplo, suponha que tem um método onde precisa de alocar um buffer temporário de um tamanho especificado (vamos chamar a este valor length), e depois usá-lo para realizar algum trabalho. Uma primeira versão ineficiente pode ter esta aparência:
byte[] buffer = new byte[length];
// Use buffer here
Esta versão não é ideal porque aloca um novo buffer sempre que usas este código, e depois descarta-o imediatamente. Esta abordagem coloca mais pressão no coletor de lixo. Pode otimizar o código anterior 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);
}
O código anterior aluga um buffer de um pool de arrays, mas é mais prolixo e propenso a erros. Tem de ter cuidado com o try/finally bloco para garantir que devolvas sempre o buffer alugado ao pool. Pode reescrevê-lo usando a tipografia SpanOwner<T> , assim:
// 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
A SpanOwner<T> instância aluga internamente um array e trata de o devolver ao pool quando este sai do âmbito. Também já não precisas de usar um try/finally bloco, pois o compilador C# adiciona isso automaticamente ao expandir essa using instrução. Assim, pode ver o tipo SpanOwner<T> como um wrapper leve em torno das ArrayPool<T> APIs. Torna-os ambos mais compactos e fáceis de usar, reduzindo a quantidade de código que necessita escrever para alugar e libertar corretamente buffers de curta duração. Você pode ver como o uso SpanOwner<T> torna o código muito mais curto e direto.
Observação
Como este é um tipo exclusivo para pilha, ele depende do padrão de tipagem de pato introduzido no C# 8. Este padrão é mostrado no exemplo anterior: o SpanOwner<T> tipo é usado dentro de um using bloco apesar de o tipo não implementar a IDisposable interface de forma alguma, e também nunca é encaixotado. A funcionalidade é exatamente a mesma: assim que o buffer sai do escopo, ele é automaticamente descartado. As APIs em SpanOwner<T> dependem deste padrão para desempenho adicional: assumem que o buffer subjacente nunca é descartado enquanto o tipo SpanOwner<T> estiver dentro do escopo. Eles não realizam as verificações adicionais que são feitas em MemoryOwner<T> para garantir que o buffer ainda está disponível antes de devolver uma instância de Memory<T> ou Span<T>. Por isso, use sempre este tipo com um using bloco ou expressão. Não o fazer faz com que o buffer subjacente não seja devolvido ao pool partilhado. Tecnicamente, pode obter o mesmo resultado ao chamar manualmente o tipo SpanOwner<T> em Dispose (o que não requer C# 8), mas essa abordagem é sujeita a erros e, por isso, não é recomendada.
Exemplos
Pode encontrar mais exemplos nos testes unitários
.NET Community Toolkit