Neu in .NET 8.0 [13]: Leistung von FrozenSet

Eine Menge des Typs FrozenSet gewinnt beim tausendmaligen Aufruf von Contains() gegenüber anderen Objektmengen.

In Pocket speichern vorlesen Druckansicht 4 Kommentare lesen

(Bild: Daniel Tadevosyan/Shutterstock.com)

Lesezeit: 1 Min.
Von
  • Dr. Holger Schwichtenberg

Im vorherigen Teil dieser Serie habe ich die Klasse FrozenSet<T> im Namensraum System.Collections.Frozen vorgestellt, die neu in .NET 8.0 ist. Es stellt sich die Frage, warum denn Microsoft FrozentSet<T> zusätzlich eingeführt hat. Die Antwort der Frage ist – wie so oft – Performance.

Der Dotnet-Doktor – Holger Schwichtenberg

Dr. Holger Schwichtenberg ist technischer Leiter des Expertennetzwerks www.IT-Visions.de, das mit 53 renommierten Experten zahlreiche mittlere und große Unternehmen durch Beratungen und Schulungen sowie bei der Softwareentwicklung unterstützt. Durch seine Auftritte auf zahlreichen nationalen und internationalen Fachkonferenzen sowie mehr als 90 Fachbücher und mehr als 1500 Fachartikel gehört Holger Schwichtenberg zu den bekanntesten Experten für .NET und Webtechniken in Deutschland.

Diesmal bewerte ich anhand eines typischen Einsatzbeispiels die Geschwindigkeit.

Gegeben sei eine unsortierte Menge der Zahlen zwischen 1 und 10.000. Wie schnell kann man eine einzelne Zahl in der Menge finden?

Für die Leistungsmessung kommt die Bibliothek BenchmarkDotNet von Microsoft zum Einsatz.

using System.Collections.Frozen;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Toolchains.InProcess.NoEmit;
 
namespace NET8_Console.Collections_Benchmark;
 
public class AntiVirusFriendlyConfig : ManualConfig
{
 public AntiVirusFriendlyConfig()
 {
  AddJob(Job.MediumRun
      .WithToolchain(InProcessNoEmitToolchain.Instance));
 }
}
 
[Config(typeof(AntiVirusFriendlyConfig))]
public class Collections_Contains_Benchmark
{
 private const int Iterations = 1000;
 private readonly List<int> list;
 private readonly ReadOnlyCollection<int> roCollection;
 private readonly FrozenSet<int> frozenSet;
 private readonly HashSet<int> hashSet;
 private readonly ImmutableList<int> immutableList;
 private readonly ImmutableHashSet<int> immutableHashSet;
 
 public Collections_Contains_Benchmark()
 {
  var array = Enumerable.Range(1, 10000).ToArray();
  Random.Shared.Shuffle<int>(array);
  list = array.ToList();
  // liefert ReadOnlyCollection<T>:
  roCollection = list.AsReadOnly(); 
  frozenSet = list.ToFrozenSet();
  hashSet = list.ToHashSet();
  immutableList = list.ToImmutableList();
  immutableHashSet = list.ToImmutableHashSet();
 }
 
 [Benchmark(Baseline = true)]
 public void ListContains()
 {
  for (var i = 0; i < Iterations; i++)
  {
   var b = list.Contains(i);
  }
 }
 
 [Benchmark]
 public void ReadOnlyCollectionContains()
 {
  for (var i = 0; i < Iterations; i++)
  {
   var b = roCollection.Contains(i);
  }
 }
 
 [Benchmark]
 public void FrozenSetContains()
 {
  for (var i = 0; i < Iterations; i++)
  {
   var b = frozenSet.Contains(i);
  }
 }
 
 [Benchmark]
 public void HashSetContains()
 {
  for (var i = 0; i < Iterations; i++)
  {
   var b = hashSet.Contains(i);
  }
 }
 
 [Benchmark]
 public void ImmutableListContains()
 {
  for (var i = 0; i < Iterations; i++)
  {
   var b = immutableList.Contains(i);
  }
 }
 
 [Benchmark]
 public void ImmutableHashSetContains()
 {
  for (var i = 0; i < Iterations; i++)
  {
   var b = immutableHashSet.Contains(i);
  }
 }
}

Der in der folgenden Abbildung dargestellte Benchmark ruft 1000-mal die Methode Contains() auf einer unsortierten Liste mit 10.000 Zahlen auf. Die Menge des Typs FrozenSet gewinnt beim 1000-maligen Aufruf von Contains() gegenüber anderen Objektmengen.

Abbildung: Eine Menge des Typs FrozenSet bringt im Vergleich deutlich höhere Performance beim 1000-maligen Aufruf von Contains().

(Bild: Screenshot (Holger Schwichtenberg))

Die Serie zu den Neuerungen in .NET 8.0

(rme)