Come eseguire il benchmark del codice C # utilizzando BenchmarkDotNet

BenchmarkDotNet è una libreria .NET leggera, open source e potente che può trasformare i tuoi metodi in benchmark, tenere traccia di tali metodi e quindi fornire informazioni sui dati sulle prestazioni acquisiti. È facile scrivere benchmark BenchmarkDotNet e anche i risultati del processo di benchmarking sono facili da usare.

È possibile sfruttare BenchmarkDotNet per eseguire il benchmarking di applicazioni .NET Framework e .NET Core. In questo articolo esploreremo come possiamo lavorare con BenchmarkDotNet in .NET Core. Puoi trovare BenchmarkDotNet su GitHub.

Per lavorare con gli esempi di codice forniti in questo articolo, dovresti avere Visual Studio 2019 installato nel tuo sistema. Se non hai già una copia, puoi scaricare Visual Studio 2019 qui. 

Crea un progetto di applicazione console in Visual Studio

Prima di tutto, creiamo un progetto di applicazione console .NET Core in Visual Studio. Supponendo che Visual Studio 2019 sia installato nel sistema, seguire i passaggi descritti di seguito per creare un nuovo progetto di applicazione console .NET Core in Visual Studio.

  1. Avvia l'IDE di Visual Studio.
  2. Fai clic su "Crea nuovo progetto".
  3. Nella finestra "Crea nuovo progetto", seleziona "App Console (.NET Core)" dall'elenco dei modelli visualizzati.
  4. Fare clic su Avanti.
  5. Nella finestra "Configura il tuo nuovo progetto" mostrata di seguito, specifica il nome e la posizione per il nuovo progetto.
  6. Fare clic su Crea.

Questo creerà un nuovo progetto di applicazione console .NET Core in Visual Studio 2019.

Notare che quando si crea il progetto dell'applicazione console, la classe Program risultante (generata automaticamente nel file Program.cs) sarà simile a questa:

programma di classe

{

   static void Main (string [] args)

  {

      Console.WriteLine ("Hello World!");

  }

}

Useremo questo progetto e la classe Program per lavorare con BenchmarkDotNet nelle sezioni successive di questo articolo.

Installa il pacchetto NuGet BenchmarkDotNet

Per lavorare con BenchmarkDotNet è necessario installare il pacchetto BenchmarkDotNet. Puoi farlo tramite NuGet Package Manager all'interno dell'IDE di Visual Studio 2019 o eseguendo il comando seguente nella console di NuGet Package Manager:

Benchmark pacchetto di installazioneDotNet

Perché il codice di benchmark?

Un benchmark è una misurazione o un insieme di misurazioni relative alle prestazioni di un pezzo di codice in un'applicazione. Il codice di benchmarking è essenziale per comprendere le metriche delle prestazioni dei metodi nell'applicazione. È sempre un buon approccio avere le metriche a portata di mano quando si ottimizza il codice. È molto importante per noi sapere se le modifiche apportate al codice hanno migliorato o peggiorato le prestazioni. Il benchmarking aiuta anche a restringere le parti del codice dell'applicazione che necessitano di refactoring.

Passaggi per il benchmarking del codice utilizzando BenchmarkDotNet

Per eseguire BenchmarkDotNet nella tua applicazione .NET Framework o .NET Core devi seguire questi passaggi:

  1. Aggiungi il pacchetto NuGet necessario
  2. Aggiungi attributi di benchmark ai tuoi metodi
  3. Crea un'istanza BenchmarkRunner
  4. Eseguire l'applicazione in modalità di rilascio

Crea una classe di benchmarking in .NET Core

Apri il file Program.cs e scrivi il codice seguente.

  [MemoryDiagnoser]

   classe pubblica MemoryBenchmarkerDemo

    {

        int NumberOfItems = 100000;

        [Prova delle prestazioni]

        stringa pubblica ConcatStringsUsingStringBuilder ()

        {

            var sb = new StringBuilder ();

            for (int i = 0; i <NumberOfItems; i ++)

            {

                sb.Append ("Hello World!" + i);

            }

            return sb.ToString ();

        }

        [Prova delle prestazioni]

        stringa pubblica ConcatStringsUsingGenericList ()

        {

            var list = new List (NumberOfItems);

            for (int i = 0; i <NumberOfItems; i ++)

            {

                list.Add ("Hello World!" + i);

            }

            elenco di ritorno.ToString ();

        }

    }

Il programma precedente illustra come scrivere metodi per il benchmarking. Notare l'utilizzo dell'attributo Benchmark in cima a ciascuno dei metodi che devono essere confrontati.

Nel metodo Main del file Program.cs è necessario specificare il punto di partenza iniziale: la classe BenchmarkRunner. Questo è un modo per informare BenchmarkDotNet di eseguire benchmark sulla classe specificata. Quindi, sostituire il codice predefinito del metodo Main nel file Program.cs utilizzando il seguente frammento di codice.

static void Main (string [] args)

{

   var summary = BenchmarkRunner.Run ();

}

Esegui il benchmark nella tua applicazione .NET Core

Se esegui l'applicazione in modalità debug, ecco il messaggio di errore che vedrai:

Durante il benchmarking dovresti sempre assicurarti di eseguire il tuo progetto in modalità di rilascio. Il motivo è che durante la compilazione il codice viene ottimizzato in modo diverso per entrambe le modalità di debug e di rilascio. Il compilatore C # esegue alcune ottimizzazioni in modalità di rilascio che non sono disponibili in modalità di debug.

Quindi dovresti eseguire il tuo progetto solo in modalità di rilascio. Per eseguire il benchmarking, specificare il comando seguente al prompt dei comandi di Visual Studio.

dotnet run -p BenchmarkDotNetDemo.csproj -c Release

Per ottenere i migliori risultati, è necessario assicurarsi che tutte le applicazioni siano chiuse e tutti i processi non necessari interrotti prima di eseguire i benchmark.

Si noti che se non si specifica il parametro di configurazione, il runtime tenterà di eseguire il benchmarking su codice in modalità di debug non ottimizzato. E ti verrà presentato lo stesso errore mostrato nella Figura 1.

Analizza i risultati del benchmarking

Una volta completata l'esecuzione del processo di benchmarking, nella finestra della console verrà visualizzato un riepilogo dei risultati. La sezione di riepilogo contiene informazioni relative all'ambiente in cui sono stati eseguiti i benchmark, come la versione BenchmarkDotNet, il sistema operativo, l'hardware del computer, la versione .NET, le informazioni sul compilatore e le informazioni relative alle prestazioni dell'applicazione.

Verranno inoltre creati alcuni file nella cartella BenchmarkDotNet.Artifacts nella cartella principale dell'applicazione. Ecco un riepilogo dei risultati. 

Come evidente dal riepilogo mostrato nella Figura 2, per ogni metodo confrontato, vedrai una riga di dati che specifica le metriche delle prestazioni come il tempo medio di esecuzione, le raccolte Gen 0, Gen 1, Gen 2 e così via.

Esaminando i risultati mostrati nella Figura 3, è possibile vedere che ConcatStringUsingGenericList è molto più veloce del metodo ConcatStringUsingStringBuilder. Puoi anche vedere che ci sono molte altre allocazioni dopo aver eseguito il metodo ConcatStringUsingStringBuilder.

Ora aggiungi l'attributo RankColumn sopra la classe MemoryBenchmarkerDemo. Ciò aggiungerà una colonna in più all'output che indica quale metodo è stato più veloce. Eseguire nuovamente il processo di benchmarking utilizzando il seguente comando.

dotnet run -p BenchmarkDotNetDemo.csproj -c Release

Quando si esegue questo comando, viene avviato il processo di benchmarking e viene visualizzato l'output dopo che il processo di benchmarking è stato eseguito correttamente. La Figura 4 di seguito mostra l'output con l'aggiunta di RankColumn. 

BenchmarkDotNet è un ottimo strumento che fornisce un modo semplice per prendere una decisione informata sulle metriche delle prestazioni della tua applicazione. In BenchmarkDotNet, il richiamo di un metodo con l'attributo Benchmark impostato è noto come operazione. Un'iterazione è il nome dato a una raccolta di diverse operazioni. 

È possibile esplorare un'applicazione ASP.NET Core dimostrativa che illustra diversi modi per eseguire il benchmark del codice. È possibile ottenere l'applicazione dal repository ASP.NET su GitHub. 

Come fare di più in C #: 

  • Come unit test dei metodi statici in C #
  • Come eseguire il refactoring di oggetti God in C #
  • Come usare ValueTask in C #
  • Come usare l'immutabilità in C
  • Come usare const, readonly e static in C #
  • Come usare le annotazioni dei dati in C #
  • Come lavorare con i GUID in C # 8
  • Quando usare una classe astratta e un'interfaccia in C #
  • Come lavorare con AutoMapper in C #
  • Come usare le espressioni lambda in C #
  • Come lavorare con i delegati Action, Func e Predicate in C #
  • Come lavorare con i delegati in C #
  • Come implementare un semplice logger in C #
  • Come lavorare con gli attributi in C #
  • Come lavorare con log4net in C #
  • Come implementare il modello di progettazione del repository in C #
  • Come lavorare con la riflessione in C #
  • Come lavorare con Filesystemwatcher in C #
  • Come eseguire l'inizializzazione pigra in C #
  • Come lavorare con MSMQ in C #
  • Come lavorare con i metodi di estensione in C #
  • Come utilizzare espressioni lambda in C #
  • Quando usare la parola chiave volatile in C #
  • Come utilizzare la parola chiave yield in C #
  • Come implementare il polimorfismo in C #
  • Come creare il proprio pianificatore di attività in C #
  • Come lavorare con RabbitMQ in C #
  • Come lavorare con una tupla in C #
  • Esplorazione di metodi virtuali e astratti in C #
  • Come utilizzare Dapper ORM in C #
  • Come utilizzare il modello di progettazione del peso mosca in C #