Artikel uit SND Magazine 145
Begin november is er weer een nieuwe versie van .NET gereleased. Versie 7 van .NET is een current version, waarbij de support dus korter is dan die van een Long-Term Support (LTS) versie. Met de 18 maanden support die we op .NET 7 krijgen, loopt deze dus een half jaar eerder af dan de support op .NET 6. Dit betekent niet dat je deze versie van .NET links moet laten liggen, want er zijn weer tal van verbeteringen en optimalisaties doorgevoerd. In dit artikel neem ik je mee door de belangrijkste.
Compilerverbeteringen
Als ontwikkelaar maak ik graag gebruik van een hogere abstractie taal als C# en het bijbehorende .NET platform, zodat ik me geen zorgen hoef te maken over tal van zaken rond de compiler en de runtime. Hierdoor voelen verbeteringen aan de compiler soms ook minder relevant, terwijl hier op een dergelijk niveau vaak de grootste winst ten aanzien van performance wordt geboekt. Ook in .NET 7 zitten weer tal van deze verbeteringen, zoals Native Ahead-of-Time (AoT) compilation, welke het mogelijk maakt om ook op omgevingen uit te rollen, waar Just-in-Time (JiT) compilation niet wordt ondersteund. Daarnaast starten je applicaties ook nog eens sneller.
Naast tal van andere compiler verbeteringen rond geheugenallocatie, ondersteuning van diverse runtimes, algoritme optimalisatie, veiligheidsupdates en verbeteringen aan de command-line interface (CLI), zijn er ook concretere verbeteringen te ontdekken in .NET 7 die een meer functionele impact hebben.
DateTime.Nanosecond
Het DateTime type wordt uitgebreid met properties die meer zeggen dan het abstracte Ticks en ook nog met een grotere nauwkeurigheid. Vanaf .NET 7 worden namelijk ook micro- en nanoseconden ondersteund.
JSON serialisatie
Jarenlang werd de discussie Newtonsoft.Json vs System.Text.Json met bijna net zoveel passie gevoerd als de discussie tabs vs spaties. Fervente voorvechters van beide bibliotheken kwamen met allerhande voors en tegens, waarbij vaak het doorslaggevende argument was dat System.Text.Json niet feature complete was. Met .NET 7 worden er een aantal veelgevraagde en langverwachte features toegevoegd aan System.Text.Json zoals polymorphism en meer controle over het niveau en opties van serialisatie. Hoewel feature parity geen doel op zich is voor het System.Text.Json team, worden de scenarios die enkel in Newtonsoft.Json worden ondersteund wel steeds exotischer.
Generic math
In .NET 7 is het door de feature static virtual members in interfaces mogelijk om generieke implementaties te schrijven waarbij de input wordt beperkt tot numerieke waarden en je dus niet voor elk numeriek type een vergelijkbare implementatie hoeft te schrijven, maar dit op kan lossen middels generics. Waar je dus voorheen voor een double, een integer en een decimal drie verschillende implementaties moest schrijven, kan je nu af met:
C# 11 – Syntactic sugar
Zoals gebruikelijk worden er ook tal van C# verbeteringen doorgevoerd in de nieuwe versie van .NET. Veel van deze verbeteringen zitten in de sfeer van syntactic sugar, zoals generieke attributen , automatische initialisatie van defaults in structs en de ondersteuning van new line breaks in string interpolation zonder deze expliciet te escapen.
C#11 – List patterns
Een nieuwe functionaliteit die verder gaat dan slechts syntactic sugar is het kunnen matchen op list patterns. Hierbij kunnen we voor een array van [1, 2, 3]:
- exact matchen op een array,
- matchen op een sequence,
- generiek matchen middels een discard pattern _
- aan het begin of einde van een array matchen middels het slice pattern …
C#11 – Spans to rule them all (or at least for System.LINQ)
Binnen C# 11 is de support voor Span weer verbeterd. De Span, of voluit de System.Span<T>, zit er al sinds C# 7.2 in, maar in de praktijk lijkt nog niet iedereen de Span te hebben omarmd.
Doordat Spans op de stack leven en niet op de managed heap kan de compiler hierop optimaliseren en is het aanzienlijke malen sneller dan collecties op de heap. Daarnaast bespaar je uiteraard ook rekenkracht doordat er geen garbage collection nodig is voor de stack, dus ook niet voor de Span<T>. Dit voordeel is ook direct een potentieel nadeel, want het geheugen wat tijdens compileren wordt gealloceerd, blijft gealloceerd.
Er zitten daarnaast ook beperkingen aan het leven op de stack. Er is geen boxing mogelijk, waardoor code die onderliggend leunt op reflection geen gebruik kan maken van Spans, aangezien daar boxing nodig is. Ook het gebruik in asynchrone code, of in lambdas, is hierdoor niet altijd mogelijk.
De afgelopen vijf jaar, sinds de introductie van Spans, zien we ondanks deze uitdagingen de Span steeds vaker terugkomen in de interne methodes van C#, waarbij we ongemerkt onder de motorkap dus toch gebruik maken van de hierboven genoemde voordelen. In C# 11 zorgt deze verbeterde support voor een potentiële gamechanger, namelijk het gebruik in System.LINQ.
Sinds C# 3 ben ik al groot voorstander van het gebruik van Language INtegrated Queries (LINQ) die in mijn ogen bijna alle code leesbaarder en beter onderhoudbaar kan maken. Aan die leesbaar- en onderhoudbaarheid hing eigenlijk altijd het prijskaartje van een verminderde performance. Wilde je een goede performance, dan was het devies om vooral geen LINQ te gebruiken.
Voor een aantal operaties in LINQ is deze matige performance nu verleden tijd. Door het onderliggende en interne gebruik van spans, is de performance van LINQ nu vele malen beter geworden. We hebben het dan niet over 2 keer zo snel, of 10 keer zo snel, maar onder de juiste omstandigheden wel 40 keer zo snel. Daarnaast is de geheugenconsumptie, door het gebruik van de stack, vrijwel nihil.
De kans is groot dat met de volgende .NET en C# versies de ondersteuning van spans verbeterd blijft worden, dus de volgende keer dat je een collectie in C# nodig hebt, overweeg dan ook een keer een span en laat LINQ niet links liggen omwille van performance.
Figuur 1 Benchmark LINQ .NET 6 vs .NET 7
Bio Roelant Dieben
Roelant is Microsoft Azure MVP en oprichter van XPRTZ.cloud. Zijn roots liggen in de software engineering en cloud architectuur en hij heeft een gezonde passie voor AI en machine learning. Ook is hij betrokken bij diverse communities als SDN, DevNetNoord en Azure Thursday.