The implementation code of using ref and Spanless thanTgreater than to improve program performance in Net Core

  • 2021-09-20 19:56:16
  • OfStack

1. Preface

Actually speaking of ref, many students already know about it. ref is a language feature of C # 7.0, which provides developers with a mechanism to return local variable references and value references.
Span is also a complex data type based on the ref syntax, and in the second half of this article I'll have an example of how to use it.

2. ref keyword

Whether it is ref or out, It is a language feature that is difficult to understand and operate. Like the operation pointer 1 in C language, This kind of high-level syntax always brings some side effects, but I don't think it has any, and not every C # developer has to have a deep understanding of these internal operation mechanisms. I think no matter what complicated things only provide people with a free choice, risks and flexibility are never compatible.

Let's look at a few examples to illustrate the similarity between references and pointers. Of course, the following usage methods can be used long before C # 7.0:


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

The above two functions use ref and unsafe pointers to complete the parameter +1, respectively.


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

The following features are available in C # 7.0:

1. ref locals (reference local variable)


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

In this example, the reference to the local i variable, x, changes the value of the i variable when the value of x is changed.

2. ref returns (return value reference)

ref returns is a powerful feature in C # 7, which is best represented by the following code, which provides a function that returns a reference to an item in the int array:


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

A reference to an item in an array is obtained by subscript. When the reference value is changed, the array will change accordingly.

3. Span

System. Span is part of the. Net Core core under the System. Memory. dll assembly. At present, this feature is independent and may be integrated into CoreFx in the future.

How to use it? The following NuGet package is referenced under the project created by. 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>

Above we saw the pointer-like (T *) way of manipulating single 1-valued objects that can be provided using the ref keyword. Basically, operating pointers are not considered a good event under the. NET system. Of course,. NET provides us with ref for safe operation of single-value references. However, single value is only a small part of the user's demand for using "pointer"; For pointers, a more common situation is when manipulating "elements" in a series of contiguous memory spaces.

Span is represented as a contiguous block of memory of a known length and type. Much like T [] or ArraySegment in many ways, it provides secure access to memory region pointers. In fact, I understand that it will be an abstraction of the pointer to the operation (void*) in. NET, and developers familiar with C/C + + should better understand what this means.

Span features the following:

The type system that abstracts all contiguous memory spaces, including arrays, unmanaged pointers, stack pointers, managed data over fixed or pinned, and references to internal regions of values
Support CLR standard object types and value types
Support generics
Support GC, unlike pointers, which need to manage release by themselves

Let's look at the definition of Span, which is syntactically and semantically related to ref:


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 {...} }
 ...
}

Next, I will use an intuitive example to illustrate the use scenario of Span; Let's take character truncation and character conversion (conversion to integer) as examples:

If there is 1 string string content = "content-length:123", To convert 123 to an integer, the usual approach is to truncate strings independent of numeric characters with Substring. The conversion code is as follows:


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");

Why use this example? This is a typical usage scenario of substring. Every time string is operated, a new string object will be generated. Of course, it is not only Substring. When int. Parse is operated repeatedly, if a large number of operations will cause pressure on GC.

Implement this algorithm using Span:


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");

Here, the algorithm of converting string into int is implemented by ReadonlySpan, which is also a typical usage scenario of Span, and the official scenario is the same. Span is suitable for the scenario of multiple reuse operations of continuous memory.

The conversion code is as follows:


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('-')){
   sign = -1; index = 1;
  }
  for (int idx = index; idx < rspan.Length; idx++){
   char c = rspan[idx];
   num = (c - '0') + num * 10;
  }
  return num * sign;
 }
}

4. Finally

The 100,000 calls of the above two pieces of code are as follows:


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

At present, the relevant support of Span is enough, it is only the most basic architecture, and CoreFx will reconstruct and implement many API using Span. It can be seen that the performance of Net Core will become more and more powerful in the future.

The above is introduced to you by this site. ref and Span are used in Net Core < T > Methods to improve the performance of the program, I hope to help you, if you have any questions welcome to leave me a message, this site will reply to you in time!


Related articles: