Profilierung von C#-Code: Engpässe finden und Anwendungen beschleunigen

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 Profiling wichtig ist

Jeder C#-Entwickler kennt die Situation: Eine Anwendung läuft langsam, aber es ist unklar, warum. Intuitive Vermutungen sind oft falsch: Code, der langsam erscheint, kann schnell sein, und "offensichtliche" Optimierungen können nutzlos sein. Hier kommt Profiling zur Rettung – eine systematische Analyse der Code-Leistung, um Engpässe zu identifizieren.

Profiling in .NET bedeutet nicht nur die Messung der Ausführungszeit. Es ist eine ganze Reihe von Techniken: von einem einfachen Stopwatch bis hin zu fortgeschrittenen Tools wie BenchmarkDotNet und PerfView. Ohne Profiling riskieren Sie, die falschen Dinge zu optimieren und Stunden mit nutzlosen Änderungen zu verbringen.

In diesem Artikel werden wir praktische Methoden zum Profiling von C#-Code durchgehen, lernen, echte Engpässe zu finden, und verstehen, welche Tools in welchem spezifischen Fall verwendet werden sollten.



1. Grundlegendes Profiling mit Stopwatch

Die einfachste Methode, die Ausführungszeit zu messen, ist die Verwendung der System.Diagnostics.Stopwatch-Klasse. Sie eignet sich für schnelle Überprüfungen und einfache Szenarien, hat jedoch Einschränkungen: hoher Overhead (Nanosekunden) und fehlende Statistik.

using System.Diagnostics;

public class SimpleProfiler{ public static void Measure() { var sw = Stopwatch.StartNew(); // Zu testender Code var list = Enumerable.Range(0, 10_000_000).ToList(); sw.Stop(); Console.WriteLine($"Zeit: {sw.ElapsedMilliseconds} ms"); }}

Wann verwenden: für grobe Schätzungen, wenn Sie eine schnelle Antwort benötigen, ohne zusätzliche Pakete zu installieren. Nicht geeignet für präzise Messungen (z. B. beim Vergleich von Algorithmen).

Nachteile: Eine einzelne Messung kann zufällig sein (GC, Hintergrundprozesse). Sie müssen sie mehrmals ausführen und die Ergebnisse mitteln – das erledigt BenchmarkDotNet bereits.



2. BenchmarkDotNet: Der Goldstandard für Benchmarks

BenchmarkDotNet ist eine Bibliothek zur Erstellung genauer und reproduzierbarer Benchmarks. Sie wärmt automatisch den JIT auf, vermeidet GC-Einflüsse und liefert detaillierte Statistiken.

Installation und grundlegendes Beispiel

// Installation: dotnet add package BenchmarkDotNetusing BenchmarkDotNet.Attributes;using BenchmarkDotNet.Running;

public class StringBenchmark{ private string _text = "Hallo, Welt!"; [Benchmark] public bool ContainsWithOrdinal() => _text.Contains("Welt", StringComparison.Ordinal); [Benchmark] public bool ContainsWithInvariant() => _text.Contains("Welt", StringComparison.InvariantCulture);}

class Program{ static void Main() => BenchmarkRunner.Run<StringBenchmark>();}

Das Ergebnis wird zeigen, dass Ordinal 2-3 Mal schneller ist. Ohne einen Benchmark hätten Sie dies nicht bemerkt.

Erweiterte Funktionen

  • Params: Testen mit verschiedenen Datengrößen.
  • MemoryDiagnoser: Zeigt Speicherzuweisungen an.
  • Baseline: Leistung mit einer Referenz vergleichen.
[MemoryDiagnoser]public class ListBenchmark{    [Params(100, 1000, 10000)]    public int N;        private List<int> _list;        [GlobalSetup]    public void Setup() => _list = Enumerable.Range(0, N).ToList();        [Benchmark(Baseline = true)]    public int ForLoop()    {        int sum = 0;        for (int i = 0; i < _list.Count; i++) sum += _list[i];        return sum;    }        [Benchmark]    public int ForeachLoop()    {        int sum = 0;        foreach (var item in _list) sum += item;        return sum;    }}


3. Speicher- und GC-Profiling

Speicherlecks und häufige Garbage-Collection sind eine häufige Ursache für Verlangsamungen in .NET. Verwenden Sie zur Analyse:

3.1. Memory Profiler (JetBrains dotMemory)

Blogs

Buchempfehlungen