Neu in .NET 8.0 [13]: Leistung von FrozenSet
Eine Menge des Typs FrozenSet gewinnt beim tausendmaligen Aufruf von Contains() gegenĂĽber anderen Objektmengen.
- 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.
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.
(rme)