SpanOwner<T>
공유 SpanOwner<T>
메모리 풀에서 버퍼를 임대하는 스택 전용 버퍼 형식입니다. 기본적으로 형식이 아닌 기능의 MemoryOwner<T>
미러링 ref struct
입니다. 이 기능은 값을 만들 SpanOwner<T>
때 메모리 할당이 전혀 필요하지 않으므로 동기 코드(인스턴스가 필요하지 Memory<T>
않음)에만 사용되는 수명이 짧은 버퍼와 타이트 루프에서 실행되는 코드에 특히 유용합니다.
플랫폼 API:
SpanOwner<T>
,MemoryOwner<T>
구문
스택 전용인 것을 제외하고 이 형식에도 동일한 핵심 기능을 MemoryOwner<T>
적용하고, 구현과 속성이 부족하다는 사실을 제외하면 적용됩니다 IMemoryOwner<T>
interface
Memory<T>
.struct
구문은 위에서 언급한 차이점을 제외하고 함께 사용되는 구문과 MemoryOwner<T>
거의 동일합니다.
예를 들어 지정된 크기의 임시 버퍼를 할당한 다음(이 값을 length
호출하자) 메서드를 사용하여 일부 작업을 수행해야 한다고 가정해 보겠습니다. 첫 번째 비효율적인 버전은 다음과 같습니다.
byte[] buffer = new byte[length];
// Use buffer here
이 코드가 사용될 때마다 새 버퍼를 할당한 다음(문서에 언급된 MemoryOwner<T>
대로) 즉시 버퍼를 throw하여 가비지 수집기에 더 많은 압력을 가하기 때문에 이상적이지 않습니다. 다음을 사용하여 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);
}
위의 코드는 배열 풀에서 버퍼를 임대하지만 자세한 내용과 오류가 발생하기 쉽습니다. 항상 임대 버퍼를 풀에 반환하도록 블록에 주의 try/finally
해야 합니다. 다음과 같이 형식을 사용하여 다시 작성할 SpanOwner<T>
수 있습니다.
// 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
인스턴스는 SpanOwner<T>
내부적으로 배열을 임대하고 범위를 벗어나면 풀로 반환하는 작업을 처리합니다. C# 컴파일러가 해당 using
문을 확장할 때 자동으로 추가하므로 더 이상 블록을 사용할 try/finally
필요가 없습니다. 따라서 이 형식은 SpanOwner<T>
API를 중심으로 ArrayPool<T>
간단한 래퍼로 표시되어 더 간결하고 사용하기 쉽기 때문에 수명이 짧은 버퍼를 적절히 임대하고 삭제하기 위해 작성해야 하는 코드의 양을 줄일 수 있습니다. 코드를 사용하여 SpanOwner<T>
코드를 훨씬 짧고 간단하게 만드는 방법을 확인할 수 있습니다.
참고 항목
스택 전용 형식이므로 C# 8에서 도입된 오리 형식 IDisposable
패턴을 사용합니다. 이는 위의 샘플에 나와 있습니다. SpanOwner<T>
형식이 인터페이스를 using
전혀 구현 IDisposable
하지 않고 상자가 지정되지 않음에도 불구하고 블록 내에서 형식이 사용되고 있습니다. 기능은 동일합니다. 버퍼가 범위를 벗어나면 자동으로 삭제됩니다. API SpanOwner{T}
는 추가 성능을 위해 이 패턴을 사용합니다. 즉, 형식이 범위에 있는 한 SpanOwner<T>
기본 버퍼가 삭제되지 않을 것이라고 가정하고, 버퍼를 반환 Memory<T>
하기 Span<T>
전에 버퍼를 실제로 계속 사용할 수 있는지 확인하기 위해 수행 MemoryOwner<T>
되는 추가 검사를 수행하지 않습니다. 따라서 이 형식은 항상 블록 또는 식과 using
함께 사용해야 합니다. 이렇게 하지 않으면 기본 버퍼가 공유 풀로 반환되지 않습니다. 기술적으로도 형식(C# 8이 필요하지 않음)을 수동으로 호출 Dispose
SpanOwner<T>
하여 동일한 작업을 수행할 수 있지만 오류가 발생하기 쉬우므로 권장되지 않습니다.
예제
단위 테스트에서 더 많은 예제를 찾을 수 있습니다.
.NET Community Toolkit