Language/C#

[C#] Span

리네엔 2024. 11. 12. 23:19
  • BigInteger 구현을 하면서 최적화 하기 위한 방법을 찾던중 Span라는 문법을 발견.

Span<T>란?

Span<T>는 C# 7.2에서 도입된 구조체로, 연속된 메모리 영역을 안전하고 효율적으로 처리할 수 있도록 도와줌. Span<T>는 기본적으로 배열, 문자열, 혹은 포인터와 같은 연속된 메모리 공간에 대한 뷰를 제공함. 이를 통해 메모리를 복사하지 않고도 데이터를 조작할 수 있어 성능을 크게 개선할 수 있음.

기본적인 특징은 다음과 같음:

  • 메모리 안전성: Span<T>는 배열을 다룰 때 흔히 발생할 수 있는 인덱스 범위 초과 문제에 대해 안전한 처리를 제공.
  • 힙 할당 회피: Span<T>는 스택에 할당되어 GC(가비지 컬렉션)의 부담을 줄이므로, 특히 성능이 중요한 코드에서 유용.
  • 범용성: Span<T>는 배열뿐만 아니라 메모리의 특정 구역을 다루는 데도 사용할 수 있음. 문자열 조작이나 네이티브 메모리와의 상호작용에서도 효율적.

Span<T>를 사용해야 할까?

대부분의 경우, 배열과 같은 데이터를 조작할 때 메모리 복사가 성능 저하의 원인이 될 수 있음. 예를 들어, 큰 배열에서 일부 구간만 처리하고 싶을 때, 기존에는 부분 배열을 새로 생성하여 복사하는 방법을 사용. 그러나 이 과정에서 추가적인 메모리 할당과 복사가 발생해 성능이 저하될 수 있음.

Span<T>를 사용하면 이러한 문제를 해결할 수 있음. Span<T>는 원본 데이터를 가리키는 뷰만 생성하므로 메모리 할당 없이도 부분 데이터를 효율적으로 조작할 수 있음.

Span<T> 사용 예제

using System;

class Program
{
    static void Main()
    {
        int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        // 배열의 일부를 나타내는 Span 생성
        Span<int> part = new Span<int>(numbers, 2, 5); // 인덱스 2부터 5개의 요소

        // Span을 이용해 데이터 수정
        for (int i = 0; i < part.Length; i++)
        {
            part[i] *= 2;
        }

        // 결과 출력
        Console.WriteLine(string.Join(", ", numbers));
    }
}

위 예제에서는 numbers 배열에서 인덱스 2부터 시작하는 5개의 요소에 대한 Span을 생성하고, 이를 이용해 해당 요소들의 값을 두 배로 증가. Span을 통해 데이터를 변경하면 원본 배열도 함께 수정됨. 이는 메모리 복사 없이 원본 데이터를 직접 다루기 때문에 가능.

ReadOnlySpan<T>

Span<T>의 읽기 전용 버전인 ReadOnlySpan<T>도 있음. 이는 데이터를 변경할 필요가 없을 때 사용되며, 안전한 읽기 작업만을 제공함. 예를 들어 문자열을 조작할 때, 복사 없이 읽기 전용으로 사용하고자 할 때 매우 유용.

주의 사항

  • Span<T>는 스택 할당을 사용하기 때문에 메서드나 함수 범위를 벗어나면 사용할 수 없음. 따라서 Span<T>를 필드로 저장하거나 비동기 메서드에서 직접 사용할 수 없음.
  • Span<T>는 포인터와 유사한 방식으로 메모리에 접근하지만, 안전성을 제공하기 때문에 포인터의 복잡함 없이도 효율적으로 메모리를 관리할 수 있음.

'Language > C#' 카테고리의 다른 글

[C#] Skip  (0) 2024.11.06
[C#] Reflection - MemberInfo/FieldInfo / PropertyInfo  (0) 2024.10.30
[C#] Const와 Readonly  (0) 2024.10.14
[C#] Serialization & Deserializaton  (0) 2024.10.14
[C#] String Builder  (0) 2024.10.14