>  기사  >  백엔드 개발  >  코드 분석: ref 및 Span를 사용하여 .Net Core에서 프로그램 성능 향상

코드 분석: ref 및 Span를 사용하여 .Net Core에서 프로그램 성능 향상

巴扎黑
巴扎黑원래의
2017-08-14 11:53:121683검색

이 글에서는 프로그램 성능 향상을 위해 .Net Core에서 ref와 Span8742468051c85b06f0a0af9e3e506b5c를 활용하는 간단한 구현 코드를 주로 소개합니다. 필요하신 분들은 참고하시면 됩니다.

1. 서문

실제로 ref에 옴, 많은 학생들 이미 익숙함 ref는 개발자에게 지역 변수 참조 및 값 참조를 반환하는 메커니즘을 제공하는 C# 7.0의 언어 기능입니다.
Span은 ref 구문을 기반으로 하는 복잡한 데이터 유형이기도 합니다. 기사 후반부에는 이를 사용하는 방법을 보여주는 예제가 있습니다.

2. Ref 키워드

ref든 out key든 이해하고 조작하기 어려운 언어 기능입니다. C 언어의 연산 포인터처럼 이런 고급 구문은 항상 부작용을 가져오지만. 나는 이것이 아무것도 아니라고 생각하며 모든 C# 개발자가 이러한 내부 작업 메커니즘을 깊이 이해할 필요는 없다고 생각합니다. 복잡성이 무엇이든 사람들에게 자유로운 선택과 위험을 제공할 뿐이며 유연성은 결코 호환되지 않습니다. .

참조와 포인터 간의 유사성을 설명하기 위해 몇 가지 예를 살펴보겠습니다. 물론 C# 7.0 이전에는 다음 사용 방법을 사용할 수 있습니다.


public static void IncrementByRef(ref int x)
{
 x++;
}
public unsafe static void IncrementByPointer(int* x)
{
 (*x)++;
}

위의 두 함수는 각각 ref 및 안전하지 않은 포인터를 사용합니다. 매개변수 +1을 완성합니다.


int i = 30;
IncrementByRef(ref i);
// i = 31
unsafe{
 IncrementByPointer(&i);
}
// i = 32

다음은 C# 7.0에서 제공하는 기능입니다.

1.ref locals (로컬 변수 참조)


int i = 42;
ref var x = ref i;
x = x + 1;
// i = 43

이 예에서는 로컬 i의 참조 x입니다. 변수, x를 변경할 때 i 변수의 값도 변경되었습니다.

2.ref 반환(반환 값 참조)

ref 반환은 C# 7의 강력한 기능입니다. 다음 코드는 해당 기능을 가장 잘 반영합니다. 이 함수는 int 배열의 항목에 대한 참조를 제공합니다.

public static ref int GetArrayRef(int[] items, int index) => ref items[index];

아래 첨자를 통해 배열에 있는 항목의 참조를 가져옵니다. 참조 값이 변경되면 배열도 그에 따라 변경됩니다.

3. Span

System.Span은 System.Memory.dll 어셈블리 아래에 있는 .Net Core 코어의 일부입니다. 현재 이 기능은 독립적이며 향후 CoreFx에 통합될 수 있습니다.

사용 방법은 무엇입니까? 다음 NuGet 패키지는 .Net Core 2.0 SDK로 생성된 프로젝트에서 참조됩니다.

 <ItemGroup>
 <PackageReference Include="System.Memory" Version="4.4.0-preview1-25305-02" />
 <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0-preview1-25305-02" />
 </ItemGroup>

위에서 우리는 ref 키워드를 사용하여 제공할 수 있는 단일 값 개체를 작동하는 포인터(T*)와 유사한 방식을 보았습니다. . 기본적으로 작동 포인터는 .NET 시스템에서 좋은 것으로 간주되지 않습니다. 물론 .NET은 단일 값 참조를 안전하게 작동하기 위한 참조를 제공합니다. 그러나 단일 값은 포인터에 대한 "포인터"를 사용하기 위한 사용자 요구의 작은 부분일 뿐이며, 더 일반적인 상황은 연속 메모리 공간에서 일련의 "요소"를 작동할 때입니다.

Span은 길이와 유형이 알려진 연속 메모리 블록으로 표현됩니다. 여러 면에서 메모리 영역 포인터에 대한 안전한 액세스를 제공한다는 점에서 T[] 또는 ArraySegment와 매우 유사합니다. 사실 저는 이것이 .NET의 작업(void*) 포인터를 추상화한 것임을 이해합니다. C/C++에 익숙한 개발자는 이것이 무엇을 의미하는지 더 잘 이해할 것입니다.

Span 기능은 다음과 같습니다.

•배열, 관리되지 않는 포인터, 스택 포인터, 고정 또는 고정된 관리 데이터, 내부 값 영역에 대한 참조를 포함한 모든 연속 메모리 공간의 유형 시스템을 추상화합니다 • CLR 표준 객체 유형 및 값 유형 지원

•제네릭 지원

•스스로 관리하고 해제해야 하는 포인터와 달리 GC 지원

구문적, 의미적으로 ref:
와 관련된 Span의 정의를 살펴보겠습니다.

public struct Span<T> {
 ref T _reference;
 int _length;
 public ref T this[int index] { get {...} }
 ...
}
public struct ReadOnlySpan<T> {
 ref T _reference;
 int _length;
 public T this[int index] { get {...} }
 ...
}

다음에는 Span의 사용 시나리오를 설명하기 위해 직관적인 예를 사용하겠습니다. 문자 가로채기 및 문자 변환(정수로 변환)을 예로 들어 보겠습니다.

문자열이 있는 경우

변환하려면 123을 변환합니다. 정수 유형인 경우 일반적인 접근 방식은 먼저 부분 문자열을 사용하여 숫자 문자와 관련이 없는 문자열을 자르는 것입니다. 변환 코드는 다음과 같습니다.

string content = "content-length:123",

string content = "content-length:123";
Stopwatch watch1 = new Stopwatch();
watch1.Start();
for (int j = 0; j < 100000; j++)
{
 int.Parse(content.Substring(15));
}
watch1.Stop();
Console.WriteLine("\tTime Elapsed:\t" + watch1.ElapsedMilliseconds.ToString("N0") + "ms");

이 예제를 사용하는 이유는 무엇입니까? . 모든 작업 String은 물론 Substring뿐만 아니라 새로운 문자열 개체를 생성합니다. int.Parse를 수행할 때 문자열 개체가 반복적으로 수행되면 GC에 부담이 됩니다.

이 알고리즘을 구현하려면

string content = "content-length:123";
ReadOnlySpan<char> span = content.ToCharArray(); 
span.Slice(15).ParseToInt();
watch.Start();
for (int j = 0; j < 100000; j++)
{
 int icb = span.Slice(15).ParseToInt();
}
watch.Stop();
Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");

문자열을 int로 변환하는 알고리즘은 ReadonlySpan을 사용하여 구현됩니다. 이는 또한 Span의 일반적인 사용 시나리오도 동일합니다. 재사용 작업. 연속 메모리 시나리오.

전환 코드는 다음과 같습니다.

public static class ReadonlySpanxtension
{
 public static int ParseToInt(this ReadOnlySpan<char> rspan)
 {
  Int16 sign = 1;
  int num = 0;
  UInt16 index = 0;
  if (rspan[0].Equals(&#39;-&#39;)){
   sign = -1; index = 1;
  }
  for (int idx = index; idx < rspan.Length; idx++){
   char c = rspan[idx];
   num = (c - &#39;0&#39;) + num * 10;
  }
  return num * sign;
 }
}


4. 마지막으로

위 두 코드를 100000번 호출하는 데 걸리는 시간은 다음과 같습니다.

String Substring Convert:
  Time Elapsed: 18ms
ReadOnlySpan Convert:
  Time Elapsed: 4ms

현재 스팬의 관련 지원 충분합니다. 가장 기본적인 아키텍처일 뿐이며 CoreFx는 Span을 사용하여 많은 API를 재구성하고 구현합니다. 앞으로 .Net Core의 성능이 점점 더 강력해질 것임을 알 수 있습니다.

위 내용은 코드 분석: ref 및 Span를 사용하여 .Net Core에서 프로그램 성능 향상의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.