The INSANE performance boost of LINQ in .NET 7

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody i'm nick and in this video i'm going to introduce you to the insane performance improvements coming to link in dot net 7 specifically around some of the methods and it's very interesting because it is not your typical oh we kinda made it a bit faster it's not twice as fast 5 times as fast or 10 times as fast it is actually up to 45 times as fast this is not performance improvement that you see every day and it's actually nothing that you can achieve with the code you will manually write instead of link and we're gonna see exactly how they achieved it and which methods are affected it is very very interesting and i think that's where dot net will go moving forward if you like that with content and you want to see more make sure you subscribe bringing this notification bell and for more training check out nick chapsters.com and speaking of that i want to let you know that i just launched my back to school sale at nickcharts.com so the first 100 of you who use discount code school2022 can get a 20 off any of my courses or any of my already discounted bundles there's only a few codes left so don't miss this opportunity now back to the video all right so let me show you what i have here so i have a simple console application here that just targets net7 and i have the dot net seven rc one installed on my pc and that's what i'm gonna be using and what i wanna show you first is the methods that got the special treatment so i'm just gonna make an enumerable and in fact we're gonna make that an array with some items and i'm going to say numerable.range starting from 1 give me 100 and then to array it and the methods with the special treatment are first max so item.max var min equals item dot min so obviously the first one gives us the max integer in this case in the array and the mean the minimum then the average is another one and also the sum so item.sum now personally i've been using max min and some quite a bit average isn't that common in my use cases but i can see how many people might be using that now historically link gets bad reputation because historically it allocates memory it is slow and even the official microsoft documentation used to say that you shouldn't be using it in hot paths where performance actually matters and that is certainly still true they don't really use it for the things that really matter when it comes to performance link usage in general in hot paths is something that could get your pr rejected in places have worked in the past so generally people would just hand roll their own solution and this is true for these things as well because at the end of the day they are link methods now what i want to do is get a baseline feel for how these used to perform in dot net 6 and before that so what i'm going to do is i'm going to change this project to dot net 6 and then i'm gonna add benchmark.net and i'm going to run some benchmarks to see where we are what's my baseline basically so we're going to do that and create a simple benchmarks class and i'm gonna add the memory diagnosis here because i want to know how memory is affected as well from one.net version to the other and this is basically the setup i want for my test so i have a size here which is defined as 100 and then i have my ionuable items and i do enumerate them as an array here we're going to talk about why that is interesting later and then my benchmarks would look something like this so min max average and sum so we're going to configure that as a release project i'm gonna go to program.cs and we're gonna say benchmark runner dot run and i'm gonna specify by benchmarks class and that's it and i'm gonna run this benchmark in dot net 6 to see exactly where we stand with performance and memory allocations and speed all right so results are back and let's see what we have here so as you can see min max average and sum they all kind of perform around the 300 nanoseconds area and then we have 32 bytes of allocated memory now what you might be tempted to do and i can totally understand why you would do so is say okay link sucks so why don't i just roll my own method to do that type of work right so you could if you wanted to do something like this to get the max item in an array for example and this maybe will be more efficient than what we have with link just to test that i'm going to comment out all the other benchmarks and i'm going to run this benchmark here and we're going to see how it compares with the link version so the one we hand rolled all right the results are back and as you can see the link version 327 nanoseconds my own version 291 a bit faster but the same memory allocated so it doesn't really matter now what i want to do is comment that hand rolled version out and uncomment all the previous ones and what i'm going to do is change this benchmark to run against dotnet 6 and dot net 7 in the same execution and i want to compare how performance changed between dot net 6 and dot net 7. now to do that and that actually might be a good lesson for you as well if you wanna get into multi-targeting and multi-target performance testing or micro benchmarking so i can change this framework to frameworks and i can use this now to say that this project targets both dot net 6 and net 7 and if you have a framework specific code you can even have if clauses and say if dot net 6 then do something and otherwise if i don't know net seven do something else this is actually a very common technique that libraries and you get packages use because they have to target all these different versions where some methods might not be available so now that i have that what i need to do to actually execute towards both is say simple job and i can specify the runtime so in my case i want net 7 and i also want net six so dot net six and dot net seven and i could even set a baseline instead of my baseline is this but i don't wanna pollute the results with columns that are a bit distracting so this is enough for what i want to do and now this class will run four benchmarks per run time so eight results in the end so let's go ahead and run that and see how dot net six performance and dot and seven performance for the exact same code compares all right so results are back and let's see what we have here so these are the dot net six numbers and these are the seven numbers now a few very interesting things first the new ones the dot net seven was are incredibly fast 9 nanoseconds from 317 8 from 300 basically 13 and 27 for average and some that is nuts this is not performance you'd expect and also zero memory allocations huh how well i'll show you how but before you start saying oh this is because you're using an array and i might be using a list i'm gonna run the same results with a two list here instead of a two array just to see where we are and i have to wait three minutes for execution so ah this is a bit boring for me but for you it's just so results are back and let's see what we have here so as you can see and you should notice that generally using lists and operating on less is usually slower and it's also a bit less memory efficient so as you can see from 32 bytes to 40 bytes and then this is 485 from 315 so as you can see the performance benefits of net 7 both in speed and allocated memory are still here and these methods still perform as if this was an array while these are slower and worse low and this is actually where the 48 times faster claim comes from because well it is but how because if i uncomment my own max version and i run it this is still 300 nanoseconds meaning that if i chose to wrote my own max method to be faster and i upgraded.net 7 will my code would be slower than what link could provide which is interesting because we know that we shouldn't be using links so what do you do well enough with that let's see how they managed to do this i'm going gonna go to min but both min and max and average and some they all have the same technique if i go to the dot net six version as you can see pretty straight forward i knew it comes in we get the enumerator we use the move next method and then we check the value and if the current value is smaller than the previous value that we had then we set that and it goes on and eventually we get the minimum but if i go back here and i say okay give me the dotnet 7 version to see how that works then it's a bit different well actually it's completely different so now min knows that this is an integer and it targets the main integer method and this method is weird so it doesn't look anything like what we had before let's start with that and as you can see the first thing we're trying to do is get the source the innumerable and try to get a span out of it a read-only span and if we can this is where we are in luck because if we cannot do that then as you can see it falls back to the previous way of doing things but in our case we can both with the list and the array so we're going to go here and what this is going to do is vectorize the search if possible now if you're not familiar with the vector class or vector 128 or vector 256 then if you really want to get to know that there's no in my opinion an easy way to explain this i'm going to link stephen's blog in the description if you want to read more because they did a lot of work with factorization to improve performance in dot net seven so i'm going to put that there in case you want to read more about that but you should know that this is trying to see if it can vectorize the search and to deem that it checks whether this is a hardware accelerated now if you go in here and you see what this returns you see false but you see this intrinsic attribute here this means that basically the value of this thing is actually set by the jit and this happens here if we are in release mode and i think we also have to be in x64 for this to actually be turned on but if it is even if it says false here in runtime it will be turned into true and it will work absolutely optimized and then it needs to be at least two vectors long to be able to operate on it but if it does then it uses vectors and it works with a span to be as efficient as possible and this is basically how we get this insane performance now again if you want to know all about that we're going to put the link in the description check it out it's a very lengthy post but if you're an absolute nerd when it comes to performance then you're going to absolutely love it well that's all i had for you for this video thank you very much for watching special thanks to my patreon to make this video as possible if you want to support this we're going to find the link description down below leave a like if you like this video subscribe what could i like to sharing the bell as well and i'll see you in the next video keep coding you
Info
Channel: Nick Chapsas
Views: 152,848
Rating: undefined out of 5
Keywords: Elfocrash, elfo, coding, .netcore, dot net, core, C#, how to code, tutorial, development, software engineering, microsoft, microsoft mvp, .net core, nick chapsas, chapsas, dotnet, .net, linq, linq performance, linq slow, linq fast, improve linq, linq c#, linq .net, linq .net 6, linq .net 7, The INSANE performance boost of LINQ in .NET 7
Id: zCKwlgtVLnQ
Channel Id: undefined
Length: 11min 33sec (693 seconds)
Published: Mon Sep 05 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.