Share via


SpanOwner<T>

공유 SpanOwner<T> 메모리 풀에서 버퍼를 임대하는 스택 전용 버퍼 형식입니다. 기본적으로 미러 기능을 MemoryOwner<T>형식으로 사용합니다ref struct. 이 기능은 값을 만들 SpanOwner<T> 때 메모리 할당이 전혀 필요하지 않으므로 동기 코드(인스턴스가 필요하지 Memory<T> 않음)에만 사용되는 수명이 짧은 버퍼와 타이트 루프에서 실행되는 코드에 특히 유용합니다.

플랫폼 API:SpanOwner<T>, MemoryOwner<T>

구문

스택 전용인 것을 제외하고 이 형식에도 동일한 핵심 기능을 MemoryOwner<T> 적용하고, 구현과 속성이 부족하다는 사실을 제외하면 적용됩니다 IMemoryOwner<T>interfaceMemory<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이 필요하지 않음)을 수동으로 호출 DisposeSpanOwner<T> 하여 동일한 작업을 수행할 수 있지만 오류가 발생하기 쉬우므로 권장되지 않습니다.

예제

단위 테스트에서 더 많은 예제를 찾을 수 있습니다.