What is Span in C# and why you should be using it

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody i'm nick anderson i'm going to explain exactly what span is in cshop and how it works and i'm going to explain to you how you can use it in your application as well today without having to make any drastic changes there's a lot of misconceptions and a lot of things you can do right but also wrong if you use a feature so i want to clear that up in this video and make sure you leave this video understanding exactly what it is how it works and how you can use it if you like content and you want to see more make sure you're subscribing this notification bell to get related when i upload a new video so let's see what i have here first i have a symbol program.cs and it has a date as a text and this is just a random format it goes by day month and then year and then here i have a method which is supposed to pass this text and then get the day the month and the year and return it as integers now let's see how you would normally do that in c sharp writing on your code there's many ways to do that you might want to split on the app space or you might want to get offset because currently it's always going to be like 2 in the beginning so 0 and something or like 21 22 and same for the month and then the year is the rest so what you can do right now if you want to is something like this you can say day as text for example and then you can say date as text dot substring and you're going to say start from 0 and get 2 and this doesn't work because this needs to be static that's fine so if i change the static this will give you uh the first two characters which is the day and then you can do the same thing for the rest so you can say month as text equal state substring and then you get from the third and length two and in the end you say year as text equals date as text dot substring and then you get from the sixth character onwards because this can be like uh any year and then if you do that you can convert them with the int.pass method to integers so it will look like this and then all you need to do is change that and now here you have it if i run this piece of code it will print back eight seven and 2021 which is this date passed as integers now here's where we have a problem you see these substrings here well strings in c sharp are immutable and they're immutable reference types meaning that if i am to debug this let's see how this looks on the memory level i'm going to load the memory here on ryder you can see all the things are located on the heap and if i press to step over these three values and i load more again you can see we have four new strings allocated and if i show you what those strings are here you can see that they are the eight the seven and the twenty twenty one that was substringed out of that main string so those are allocations on the heap those are the expensive ones because the garbage collector will have to actually find them when they get de-referenced when we're outside of this method for example and they no longer have something pointing at them and it's going to have to pause your application trigger gaps collection and remove them and that's expensive on your cpu so how can we prevent that well here's where span comes in and span actually is perfect for that sort of string manipulation so let's take the same method over here and what i'm going to do i'm going to say date with string and span instead and what i'm going to change is i'm going to say read only span here and read only span is a version of span which is read-only and i say char and you have the date as a span now and you can implicitly convert to that so all you need to do is do this and now we can use this span here here and here and we can use the slice method very similar to the substring i'm going to explain exactly how this slicing works just give me a second but i just want you to see in the beginning that i can change that to that and execute this and we have the same result however there's a major change and let's see that major change now what i'm going to do is i'm going to create a benchmark class and i'm going to put those um those methods in that class so i'm going to say benchy here and then i'm going to take those two put them here i'm going to take this one as well and put it here and i'm going to add benchmark.net which is the package that will allow us to run benchmarks on those two operations and all i need to do is remove this from being static and this and then add a benchmark header attribute and another attribute here and then i want the memory diagnoser to see how much memory is being allocated here and i'll explain why this memory thing is very interesting once we get the results back so all i need to do is say benchmark runner dot run and provide the class and then i have to change this into release mode and execute it and this will now execute both the the substring method and the slice method and we're gonna get results on how fast they are and how much memory they allocate the two things that we care about now i have to warn you if you have played with span a little bit in the past maybe when it came out in dot net core 2.1 i think um there's a lot of optimizations that went into the the speed of other operations as well so things historically like substring used to be slower significantly slower when they were pitted against span net now five has been optimized quite a bit so you won't see insane speed optimizations but that's not really what we're looking after when using span so let's see the results are back and as you can see using substring is 51 nanoseconds and using the span and the slice is 32 nanoseconds so both are very small right and yes you can say that it's almost half maybe 75 um more expensive to go with the substring but this is nowhere near as important as this memory allocation span is all about memory span and the reason why it acts as an array effectively because you know you can iterate on this character as if it was an array is that it's an arbitrary piece of memory that is guaranteed to always be on the stack meaning it can't be allocated physically on the managed heap which is the thing where gabby's collection kicks in collects and that's the expensive part because as garbage collection is running your application is not running and maybe me explaining it that way doesn't really explain the actual benefit or feature or how it works so let's go to the drawing board and see exactly how this works so here i have the the stack and the heap the two places where we can actually locate memory the hip is the expensive one where we actually have the garbage collector picking up any dangling bits any doubling things that don't have references pointing to them while the stack only lives within the stack frame and it's getting automatically disposed the moment you're outside of that frame so in that case where we were before this is what will actually happen we we want to have some text in this scenario the text is the the date so let's say something like this and now this is a string so in our scenario it's a static read-only thing so it will get treated a bit differently but imagine that this is runtime for example and you have something like this we want to create this string and this will have an address now the actual address is way longer but imagine that this is a shorter version of that address and now what we're going to do in order to refer to that string in order to use it on the stack is we're gonna store the address and then we're gonna have a pointer to it now if i do substring what's gonna happen is i'm gonna have something like this i'm gonna have 08 here so the first approach where i showed you then 07 here and 2021 here and all of these will be separate allocations because strings in c sharp are immutable and you cannot change the value of a string three and zero so all different addresses and these will be stored on the stack and you're going to have to point at them and the way it works is something like this this should be actually for cool now the problem with this is you're allocating basically double the memory on the heap and the moment this goes out of scope and it no longer has references pointing at them then those things will stay there allocated and something eventually will need to come in and gab is collected and that's expensive we don't want that now if we go back to the initial thing where we just have the string allocate the one we need here's what would happen if you had a span the span will store the address of the string it needs to deal with and then it will also store an offset let's say if in this scenario we we have a 0 and a 2 which is offset in length so start from 0 and read all the way up to 2 then what it will do is it will store 0 basically here and then in the next address here it will store the length so all it needs to do now in order to use this immutable string is get the address of the string to know where it lives in the memory and then get an offset to know which part it needs to read so this thing will point at this and we didn't need to allocate any extra memory and it's the same with all the other things if i need to read for example the month all i need to store again all the stack this is all stack allocation is the address of the original string plus the offset which in our scenario here as you can see is three and then two is the length so i can go back here and say three for the offset two for the length so this span now points here and it's the same for the year you get the original address and an offset and then you get the length and this is how span will work so it's a very simple in concept thing and i think when you visualize it this way it's way easier to understand but this is why it is so memory efficient because it only deals with existingly allocated memory not with memory that needs to allocate to make those manipulations and it's great in my opinion for things like this where you have some string you need to do some slicing or some pausing of it and you can go character by character in a loop fashion and you can say is character upper or is lower and you can do tons of things it's way more limited as an api from what you'd normally have on string but that's understandable due to how it works behind the scenes when you can make benefit of it it's just a free allocation heaven you can deal with now you might have heard me saying that a couple of times by now but spans cannot be allocated on the heap and the reason for that is because spans are ref structs and ref structs cannot be created on the heap for example if i try to make that thing here it just won't allow me because as you can see it gives you a kind of a very technical explanation but but basically because a value type on the class level is effectively going to be allocated on the heap alongside its parent when this is instantiated you cannot allocate here the compiler just won't let you it won't happen and this comes with other drawbacks as well it can't implement interfaces it can't be used on iterators or async and it can't be boxed i mean that's kind of a benefit but it also is drawback on what you can do with it so its usage is more limited and more specific but if you can use it please do now this is where it becomes more interesting let me just take this up here and put it in main so we can show you what i mean we can copy that and let's say all i want to do now is return the year from that original big string as a text so year as text right so you still get the span you only grab the year and then you return it so i can simply say return year as text to string and if i do that let me just copy that out and say console.writeline year this needs to be static and now i can say year as text right so if i do that but i get back i get 20 21 great however this is one of the things i see wrong quite a bit if you go through the trouble to actually use a string and then turn it into a span if you return back a string from the span then you're just losing all the benefit because you are still going to allocate that memory there is no point in in going about it with a slice if you're going to just return the text so ideally you want to leave it up to the consumer of the method to decide whether for them it's worth maybe to stringing it and converting it to a string or using it as a span and this is where returning the span actually makes more sense and now the user if they want to visualize it sure they can do to string and if i run this they get the same result but if what they want to do is get it and only get the let's say 21 to represent the decade then they could in return do slice from two and get the two last things and only return 21 and for them they only allocated the two bytes for the string out of the four that the span contained so you make it way more flexible for them to write better code by returning something that is more efficient again this is more specific to what you're doing and i'm not saying you should go everywhere and just return read-only spans but if you know that what you're building will be used by someone and it makes sense for them to do further work with this thing you're returning maybe returning a span instead of returning the actual value or the actual reference type might be better for them that's all i had for you for this video thank you very much for watching special next my patreon for making videos possible if you want to support me as well you're going to find it in the description down below leave a like if you like this video subscribe for more content like this sharing the bell as well and i'll see you in the next video keep coding
Info
Channel: Nick Chapsas
Views: 208,597
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, clean code, what is span in c#, span in .net, write allocation free code in c#, What is Span in C# and why you should be using it, span of t, how span works, span and memory in c#, dotnet, .net
Id: FM5dpxJMULY
Channel Id: undefined
Length: 15min 14sec (914 seconds)
Published: Tue Jul 13 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.