Aracılığıyla paylaş


SpanOwner<T>

SpanOwner<T>, paylaşılan bir bellek havuzundan arabellek kiralayan yalnızca yığın arabellek türüdür. Temelde işlevini yansıtır MemoryOwner<T>, ancak bir ref struct tür olarak. Bu özellikle yalnızca zaman uyumlu kodda kullanılan kısa süreli arabellekler (örnek gerektirmeyen Memory<T> ) ve sıkı bir döngüde çalışan kodlar için kullanışlıdır çünkü değer oluşturmak SpanOwner<T> için bellek ayırmaları gerekmez.

Platform API'leri:SpanOwner<T>, MemoryOwner<T>

Sözdizimi

Aynı temel özellikleri MemoryOwner<T> bu tür için de geçerlidir; yalnızca yığın structolması ve uygulamanın yanı sıra IMemoryOwner<T> özelliği de eksik interfaceMemory<T> olması dışında. Söz dizimi, yukarıda belirtilen farklar dışında, ile MemoryOwner<T> kullanılanla neredeyse aynıdır.

Örneğin, belirtilen boyutta geçici bir arabellek ayırmamız gereken bir yöntemimiz olduğunu varsayalım (bu değeri lengthçağıralım) ve ardından bunu kullanarak biraz çalışma gerçekleştirelim. İlk, verimsiz sürüm şu şekilde görünebilir:

byte[] buffer = new byte[length];

// Use buffer here

Bu kod her kullanıldığında yeni bir arabellek ayırdığımız ve ardından çöp toplayıcı üzerinde daha fazla baskı oluşturan (belgelerde MemoryOwner<T> de belirtildiği gibi) hemen attığımız için bu ideal değildir. kullanarak yukarıdaki ArrayPool<T>kodu iyileştirebiliriz:

// 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);
}

Yukarıdaki kod bir dizi havuzundan arabellek kiralar, ancak daha ayrıntılı ve hataya açık: kiralanan arabelleğinden havuza her zaman geri döndürmek için blokta dikkatli try/finally olmamız gerekir. Türünü kullanarak SpanOwner<T> yeniden yazabiliriz, örneğin:

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

Örnek SpanOwner<T> dahili olarak bir dizi kiralar ve kapsamın dışına çıktığında bu diziyi havuza döndürmeyi üstlenir. C# derleyicisi bu deyimi genişletirken try/finally bunu otomatik olarak ekleyeceği için artık bir using blok da kullanmamız gerekmez. Bu nedenle, SpanOwner<T> türü API'ler etrafında ArrayPool<T> basit bir sarmalayıcı olarak görülebilir, böylece hem daha kompakt hem de kullanımı daha kolay hale gelir ve kısa ömürlü arabellekleri düzgün bir şekilde kiralamak ve atmak için yazılması gereken kod miktarını azaltır. Kullanımın SpanOwner<T> kodu çok daha kısa ve daha kolay hale getirdiğini görebilirsiniz.

Not

Bu yalnızca yığın türünde olduğundan, C# 8 ile tanıtılan ördek türü IDisposable desenine dayanır. Bu, yukarıdaki örnekte gösterilmiştir: SpanOwner<T> türün arabirimi hiç uygulamadığı using ve hiçbir zaman kutulanmamış olmasına rağmen bir IDisposable blok içinde kullanılır. İşlevsellik aynıdır: arabellek kapsam dışına çıkar çıkmaz otomatik olarak atılır. içindeki API'ler SpanOwner<T> ek performans için bu desene dayanır: tür kapsam içinde olduğu sürece temel alınan arabelleğin SpanOwner<T> hiçbir zaman atılmayacaklarını varsayarlar ve arabellekten bir MemoryOwner<T> veya Memory<T> örneği döndürmeden önce aslında hala kullanılabilir olduğundan emin olmak için içinde Span<T> yapılan ek denetimleri gerçekleştirmez. Bu nedenle, bu tür her zaman bir using blok veya ifade ile kullanılmalıdır. Bunun yapılmaması, temel alınan arabelleğin paylaşılan havuza döndürülmemesine neden olur. Teknik olarak aynı işlem türü üzerinde Dispose el ile çağrılarak SpanOwner<T> da gerçekleştirilebilir (C# 8 gerektirmez), ancak bu hataya açıktır ve bu nedenle önerilmez.

Örnekler

Birim testlerinde daha fazla örnek bulabilirsiniz.