Optimierung der Leistung von C#-Anwendungen: für Anfänger

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum ist Leistung von Anfang an wichtig?

\n

Jeder C#-Entwickler stößt früher oder später auf die Situation, dass die Anwendung zu trödeln beginnt. Oft werden Leistungsprobleme in frühen Phasen verursacht – durch suboptimale Algorithmen, falsche Speicherverwaltung oder übermäßige Nutzung von LINQ ohne Verständnis seiner internen Funktionsweise. Für Anfänger mag dieses Thema komplex erscheinen, aber tatsächlich sind die grundlegenden Optimierungsprinzipien recht einfach und können in wenigen Stunden Praxis erlernt werden.

\n

In diesem Artikel werden wir vier Schlüsselaspekte behandeln, die Ihnen helfen, schnelle und effiziente C#-Anwendungen auf der .NET-Plattform zu schreiben. Sie erfahren, wie Sie Code profilieren, LINQ-Abfragen optimieren, Speicher richtig verwalten und Asynchronität nutzen. Die Codebeispiele werden so praxisnah wie möglich an realen Aufgaben sein, mit denen Entwickler konfrontiert werden.

\n\n

1. Profiling: Der erste Schritt zur Optimierung

\n

Bevor Sie etwas optimieren, müssen Sie verstehen, was genau trödelt. Intuitive Vermutungen sind oft falsch. Profiling ist der Prozess der Messung der Leistung Ihres Codes mit speziellen Werkzeugen.

\n\n

Werkzeuge für das Profiling

\n
    \n
  • Visual Studio Diagnostic Tools – integriertes Werkzeug, verfügbar in den Editionen Community und höher. Ermöglicht die Verfolgung von CPU-, Speicher- und Ausführungszeitnutzung.
  • \n
  • JetBrains dotMemory / dotTrace – leistungsstarke kommerzielle Dienstprogramme zur Analyse von Speicher und Ausführungszeit.
  • \n
  • BenchmarkDotNet – eine leichtgewichtige Bibliothek für Mikro-Benchmarking. Ideal zum Vergleich zweier Implementierungen derselben Methode.
  • \n
\n\n

Beispiel: Messung der Ausführungszeit

\n

Verwenden Sie Stopwatch für eine einfache Messung:

\n
using System.Diagnostics;\n\nvar stopwatch = Stopwatch.StartNew();\n// Ihr Code\nfor (int i = 0; i < 1000000; i++)\n{\n    // Eine Operation\n}\nstopwatch.Stop();\nConsole.WriteLine($"Ausführungszeit: {stopwatch.ElapsedMilliseconds} ms");
\n

Tipp: Verwenden Sie für genaue Messungen BenchmarkDotNet, da Stopwatch den Overhead der JIT-Kompilierung nicht berücksichtigt.

\n\n

2. Arbeit mit Speicher und Zeichenketten

\n

Die Speicherverwaltung in .NET ist automatisiert (Garbage Collector), aber das bedeutet nicht, dass man sie vergessen kann. Eines der häufigsten Probleme ist die übermäßige Erstellung von Zeichenketten.

\n\n

Problem: Zeichenkettenverkettung in einer Schleife

\n

Zeichenketten in C# sind unveränderlich. Jede +-Operation erstellt eine neue Zeichenkette, was zu ständigen Speicherzuweisungen und Druck auf den GC führt:

\n
string result = "";\nfor (int i = 0; i < 10000; i++)\n{\n    result += i.ToString(); // SCHLECHT: erstellt 10000 neue Zeichenketten\n}
\n\n

Lösung: StringBuilder

\n

Die Klasse StringBuilder arbeitet mit einem Zeichenpuffer und minimiert Speicherzuweisungen:

\n
var sb = new StringBuilder();\nfor (int i = 0; i < 10000; i++)\n{\n    sb.Append(i);\n}\nstring result = sb.ToString(); // GUT: eine Speicherzuweisung am Ende
\n\n

Boxing vermeiden

\n

Boxing (Verpacken von Werttypen in ein Objekt) ist eine weitere Quelle versteckter Speicherzuweisungen. Beispiel:

\n
ArrayList list = new ArrayList();\nlist.Add(42); // Boxing: int wird in object verpackt\n\n// Besser generische Sammlungen verwenden:\nList<int> list2 = new List<int>();\nlist2.Add(42); // Ohne Boxing
\n\n

3. Optimierung von LINQ-Abfragen

\n

LINQ ist ein mächtiges Werkzeug, aber seine falsche Verwendung kann die Anwendung stark verlangsamen. Das Hauptproblem sind mehrfache Durchläufe von Sammlungen.

\n\n

Problem: Mehrfache Iterationen

\n

Jeder Aufruf von Where(), Select(), Count() kann die Sammlung erneut durchlaufen, wenn das Ergebnis nicht materialisiert wird:

\n
var numbers = Enumerable.Range(1, 1000000);\nvar evenNumbers = numbers.Where(n => n % 2 == 0);\nint coun                

Blogs

Buchempfehlungen