Als kleines Gimmick möchte ich noch einmal einen Blick auf die Laufzeiten des vorangegangenen Beispiels werfen:
Method | Mean | Error | StdDev |
---|---|---|---|
LinqOfTypePerformance | 6.809 ms | 0.1240 ms | 0.1612 ms |
LinqCastPerformance | 1.784 ms | 0.0336 ms | 0.0373 ms |
Ich deutete bereits an, dass durch Parallelisierung eine weitere, einfache Leistungssteigerung möglich ist. Dafür erweitere ich die Benchmark-Klasse um die folgende Methode:
/// <summary>
/// Benchmark for the parallelized Linq-Cast-Performance.
/// </summary>
[Benchmark]
public double LinqParallelCastPerformance()
{
return this.fleet.AsParallel().Where(v => v.VehicleType == VehicleType.Car).Cast<Car>().Where(c => c.FuelType == FuelType.Diesel).Sum(c => c.FuelAmount);
}
Der einzige Unterschied zwischen der vorangegangenen Implementation ist die Verwendung der Erweiterungsmethode AsParallel(), welche im Namespace System.Linq zu finden ist. Diese Methode erlaubt es, Abfragen zu parallelisieren. Hierzu wird intern ein Wrapper verwendet. Je nach Anwendungszweck kommen unterschiedliche Wrapper zum Einsatz, die unterschiedliche Ansätze verfolgen. In weiteren, zukünftigen Beiträgen werde ich die Unterschiede noch entsprechend darstellen.
Eine neue Ausführung des Benchmarks zeigt nun folgendes Ergebnis:
Method | Mean | Error | StdDev |
---|---|---|---|
LinqCastPerformance | 1.751 ms | 0.0345 ms | 0.0517 ms |
LinqOfTypePerformance | 6.808 ms | 0.1342 ms | 0.1697 ms |
LinqParallelCastPerformance | 1.075 ms | 0.0208 ms | 0.0292 ms |
Die Parallelisierung macht nicht überall Sinn, sie erfordert einen gewissen Verwaltungsoverhead für die Initialisierung und die Parallelisierung. Wir arbeiten hier mit 1.000.000 Objekten, wo die Parallelisierung durchaus sinnvoll ist, wie man an den Ergebnissen erkennen kann. Weiterhin ist die Parallelisierung natürlich auch von der verwendeten Hardware abhängig. Wie genau zu erkennen ist, wie viele parallele Abarbeitungen sinnvoll sind und wie diese Parallelisierung zu steuern ist, sehen wir uns in einem der nächsten Beiträge detaillierter an.
Ein sehr schönes Feature, welches mit C# 8.0 eingeführt wurde, ist die asynchrone Unterstützung von IEnumerables: IAsyncEnumerator. Auch das ist ein Thema für einen der folgenden Beiträge. Asynchronität ist nicht gleich Parallelität, beide Ansätze können sich einander jedoch gut ergänzen oder aber auch behindern.
Schreibe einen Kommentar