String.Create

Wenn es um Performance in .net geht dann ist String.Create ein Freund. String.Create kreiert einen String sehr schnell und mit minimalen Speicher overhead.

Gerade wenn es um Performance geht, ist String immer ein kleines Hinderniss. Das hat auch damit zu tun wie Strings in .NET definiert sind.

Zur Erinnerung:

  • Strings sind Referenztypen und ihre Daten werden auf dem verwalteten Heap gespeichert.
  • Strings sind von Haus aus unveränderlich, was bedeutet, dass ihre Daten nach der Erstellung nicht mehr geändert werden können.

Schauen wir uns das mal mittels eines Beispiels an

normal

 public string GenerateShortCode_Classic()
 {
     var random = new Random();
     const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
     return new string(Enumerable.Repeat(chars, 6)
       .Select(s => s[random.Next(s.Length)]).ToArray());
 }

vs
String.create

 public string GenerateShortCode_StringCreate()
 {
     var random = new Random();
     const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";


     string result = string.Create(6, chars, (chars, buf) =>
     {
         for (int i = 0; i < chars.Length; i++) chars[i] = buf[random.Next(buf.Length)];

     });

     return result;



 }

Abgesehen davon das die String klassische Variante vielleicht lesbarer ist machen die zwei Beispiele das gleiche – es wird ein zufälliger sechs Zeichen langer String erzeugt.

Aber der Benschmark:

MethodMeanErrorStdDev
GenerateShortCode_Classic252.2 ns4.80 ns7.76 ns
GenerateShortCode_StringCreate167.8 ns3.42 ns4.45 ns

zeigt das String.Create deutlich schneller ist.

Eine interessante Funktion bei String.Create ist

public static string Create (IFormatProvider? provider, ref System.Runtime.CompilerServices.DefaultInterpolatedStringHandler handler);

Dies kann folgender maßen verwendet werden

   public string FormatProvider_StringCreate()
   {
       IFormatProvider formatProvider = CultureInfo.GetCultureInfo("en-US");
       string name = "Alice";
       int age = 30;
       decimal balance = 1234.56m;

       // Use String.Create with the IFormatProvider, a Span<char> for direct memory manipulation, and DefaultInterpolatedStringHandler
       string result = String.Create(formatProvider, $"{name} is {age} years old and has a balance of {balance:C}.");

       return result;

   }
 public string FormatProvider_ToString()
 {
     IFormatProvider formatProvider = CultureInfo.GetCultureInfo("en-US");
     string name = "Alice";
     int age = 30;
     decimal balance = 1234.56m;

     // Use String.Create with the IFormatProvider, a Span<char> for direct memory manipulation, and DefaultInterpolatedStringHandler
     string result = String.Format(formatProvider, "{0} is {1} years old and has a balance of {2:C}", name, age, balance);


     return result;

 }
MethodMeanErrorStdDevMedianGen0Allocated
FormatProvider_StringCreate206.1 ns7.34 ns21.19 ns199.2 ns0.0191160 B
FormatProvider_ToString228.9 ns4.48 ns3.74 ns228.4 ns0.0257216 B

Auch hier zeigt sich eine Verbesserung der Performance, jedoch auch das weniger Bytes verwendet werden.

String.Create

plus Punkte:

  • Schneller
  • Weniger Speicher

minus Punkte

  • Lesbarkeit

Source Code: gpiwonka/StringCreateTester: A small benchmark and test for String.Create (github.com)


Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert




Enter Captcha Here :