How to use Async/Await/Task in C#

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome everyone today we're gonna be talking about how to use async/await and tasks primarily we're gonna be talking about some pitfalls that you can run into and how you avoid them because generally there is only one way to use them and just try not to make these mistakes if you are interested about how this concept actually works go ahead and watch my previous video I'm gonna link it in the description or maybe try to put it as an annotation if I can figure out or bother to do that one we're also gonna take a look at a WPF example at the end is because it has that UI thread the old loop UI thread hopefully I can give you a mindset and how to think about these tasks when using them so Before we jump into these examples let's primarily get it clear if you did watch the previous video and you now have this image of a state machine that we're spawning constantly as soon as we put a sink in there know these states we're adding when we use a weight and the task is this bridge between the state machine in your code I want you to leave that all behind the fact that it's a state machine and stuff like that is gonna hinder your performance in terms of understanding it it's gonna give you a bunch of ideas that are not necessarily helpful all you want to be thinking of a task is it's some work that needs to be completed it doesn't matter what thread it's completed on or even if it started and ends on a different thread you don't even need to know that all you need to know is that it's some work that needs to be done it's also known as a promise or a future in other programming languages and to add to that a task it just it is what it sounds the task it's a promise something that we need to do and we really need the result of whatever work that is that's when we are waiting and all the magic that happens with a thread in the backgrounds just don't worry about it it's just nice to know what actually happens so let's go ahead and take a look at the first example of avoiding the state machine so this is probably a situation that you can find yourself in most often is you might get an interface which will ask you to implement add task or return some kind of a value from a task but you don't necessarily need to do input/output operations and by the way I'm just gonna diverge here real quick the only times you really do want to rade tasks and async/await is when you do input/output so that's communication with the database your disk drive SSD the network card the database communication is kinda the network card so it's interacting with an external source so for me an external source would be the computer I press the button and I wait for it to start so I can go ahead and write code or our application the external source is gonna be that network card that disk drive okay and the disk drive can work separately from our application so our thread doesn't work but that's again that's something I explained in the previous video so yeah the only time we want to use two async tasks and the wait is when we do input-output operation and the primary takeaway I want you to have is as soon as you put a sink you spawn a state machine okay so that's just to keep in mind that's how we avoid creating a state machine we avoid using a sink okay so coming back to the example where you have an interface and it has a task that it wants you to return from it you will want to do something along the lines of this so you might have some kind of a message and I've seen people do this so they will have hello world here and they will try to return this message and what it will do is it will give you an error right and it will say you know implicitly convert and you're like what's going on here right and the first reaction will be oh it's a task so I have to use async hey don't do this as soon as you write tasks you spawn a state machine alright it's extra code it's extra logic it's extra space that you're consuming in memory okay it's a it's it can be a micro optimization in some places but avoid doing this okay what you want to do is you want to use tasks from result okay and if you don't need to do it you don't need to return anything you can go ahead and say task complete okay I'm just gonna see you on the end here and complete a task so it compiles okay so here in both examples we have the task completed we have to implement a task but we don't actually have to do any but output so it's still sequential execution to avoid the async await and this scenario is just to use tasks top form result or test complete to initiate the completion of the task no state machine will be spawns a spawn there it's just sequential execution at this point next thing is sometimes what will happen is let's go ahead and put in here for Network you will have applied it will be a HTTP client and what will happen is you will want to get some content from this client and so we get string async and this is some site okay and what you will do is you will want to return this content okay and you will have to put a sink here in order to wait for this call but one important thing here is that content is of type string if we return the await here going to be of type task string okay it's the same type here so you want to avoid creating this async value here when you return this content here okay we're avoiding spawning a state machine but just returning the task itself okay you want to avoid storing it and returning it there are going to be situations where you actually do want the content but we get you want to hope let's say validate the content right validate we can replace it with something a little bit more generic like do something with the content okay and then we want to return the content right so if we need the contents specifically in this function we then await on it okay otherwise avoid using a sink and a weight here you actually just want to go ahead and return the content straight away okay so it's just something to catch ourself on doing this don't go out actively looking for it you can do it at the start but again this can hinder your performance in terms of the actual work you're doing we actually want to do is be like oh I actually don't need to spawn a state machine here don't go looking through all your code trying to find it Hey and by the way one thing that I'm gonna be mentioning here that's not specific to avoiding the state machine is that as soon as you use a sink or even tasks it will basically propagate through all your code your code is now bound to the task object so wait what that means is that if your index page you want to go ahead and grab the result of the input-output operation you will need to wait on it that you will need to turn this task all right don't be scared of doing this throughout your code it is okay at some point you will need to spawn the state machine and the weight in it try to avoid doing it for as long as possible okay don't sacrifice code readability or not spawning the state machine async/await exists to improve code readability okay that's his primary function if you need to do something here with the content before returning it do that okay you want readability over the state machine right but when possible avoid it right that's the primary lesson here next thing is let me actually go ahead and grab this this is not going to be so visible in this example this is why I will be using the WPF example is when we will be using the configure await function on an async method right so we have configurator wait and the only time you're gonna be using it is to pass false into it right by default it's true and all it is it means that we don't care to what thread this returns so if you watched the previous video on async await me explaining it we've already seen that behavior of configure a false so in here it doesn't really matter you're not gonna see this prominent difference in topic in web application it's more gonna be it's gonna be visible more in the WPF up but essentially the whole thing about this configure weight is that we don't care that it returns to the same thread right so if we have thread ID 1 this should be thread ID 3 and if we don't call this this should be thread ID 1 as well okay so we're basically saying return to the same thread but in a web web app it doesn't matter so you can just go ahead and at configure weight as much as possible so you you want to be using configurable weight and a web application and again I'm gonna run some code on WPF app to show you that you don't want to be doing that there but this is okay to be using and all this means and again I'm just gonna restate myself is that we don't care what thread continues the execution of this function okay if the result of this needs to return to the same thread we don't care when we say false we say we don't care that the result of this comes back to the same function alright I picked up myself a couple times but okay next thing don't a sink in constructor right do not try to force following asynchronous operations in Europe when you're constructing an object yes absolutely I think one of the worst thing you can do some people still teach it they try to show you workarounds of this don't do it please what you will have is some object and you will have a constructor and I'm gonna say never do a sink here okay it's just something you never want to do okay what I'm gonna propose to you are some are two out two alternatives okay so the first start alternative is you're gonna have a some object Factory and this is then going to have a public async task some object that is going to return and you're gonna call create okay and then you can inject whatever services HTTP client into the constructor here and when the service gets resolved you can you then call the asynchronous operation here and return your tasks from or basically some new object okay so this is essentially what you want to be doing you either want to create a factory if you have different ways in which you create this some object you probably want to factor if there is only one way that you can create this object you probably want an static func right so let's go ahead create a static function the signature is going to be the same here with async okay so what you want to do is either use the static function if that you can only create this object in one way use a factory if there is a variance in how you create this object but you still need to do some kind of asynchronous operation okay please do not put any asynchronous or operations in the constructor do not use async void in order to accomplish it and they think white is probably a whole different topic just don't go there okay if you're ever in a situation where you have to use async void it's already too late paralyzed your code all the basically led you to this point and of like go-to statements if you're in a position where you need to use a go-to statement kind of it's either a very specific scenario or you jeopardize somewhere along the way okay so the next one is probably more of an important one because I've seen this done or a lot of people complain about this as well is again let's say we have some kind of asynchronous operation so let me grab this it's here here we're basically we don't want to block our thread okay I don't know who does these but some people do these let's go ahead do the input/output so we take the task and we put it in here and usually the only times you will be in a situation where you want to block the thread is when you haven't made the parent function a sink or a task when you're not trying to wait on it to do bad every documentation that says it's bad okay you just grab the result do not do this okay this is probably one of the worst things you can do let's do another bad task wait okay these are all blocking operations the thread is gonna come here and it's gonna wait so if your process has one core your application is gonna halt hey you won't be able to process more requests another bad so you see this result here there is a different way that you can do this you can go ahead and call get a waiter and get a result so this is also bad you block the operation all of these and be avoided by simply following the rule that your async/await task is gonna be propagated from your code and being ok with it embracing it and like yeah this is just the way you need to do to do asynchronous code and not to block your thread do not try to stop the propagation through your whole boat by utilizing something like you will need to turn this a sink and actually await on the task so pollution is to propagate I don't know how to spell propagate but async/await task through your code okay and as I said all the three all the three steps before where you don't want to use it in your constructor try to avoid state machines as you're gonna be propagating your code in order not to block your threads you just want to make sure that you are applying the previous lessons to minimize the damage of the state machine and memory consumption as much as possible and keeping performance as async/await and although it does give you performance in terms of non thread blocking sequential execution is still much faster but if you're worried about that sort of thing you would be doing C++ C or rust programming in c-sharp world we're worried about readability so let's take a look at how this task can propagate throughout your application so let's say if it starts somewhere in the middle it's gonna propagate all the way back to the beginning of your application right but if we take a look at the typical program CS file of a web app it doesn't actually have any tasks in its main so what we want to do is figure out how do we start a sort of a task collection or execution and basically still remain with a non task main right so let's go ahead and do something along the lines of start app and of what it does here and when I remember how to type again right so what we'll have to make this a static void as well right so we're just gonna call store a start-up and what we want to do now is we essentially have some collection function which is just a while loop which we can do to replicate the network server or a socket server right so we're just in one loop to go ahead and keep reading from the network driver right and then we're gonna process whatever we collect except here we can do some network stuff in order to fetch something from the Internet we're gonna process this message so we might do something with the database and then if we find something interesting let's go ahead and notify and this is where we're gonna use test run to do fire-and-forget hey so how can we kick off these two processes to run side-by-side how they communicate between each other does it matter at this point let's just say that they are communicating between each other we just haven't done the implementation yet so these tasks are gonna be running side-by-side and let's say if collect blocks process can then do whatever it needs to do and they both are blocked and notify can be executed and by the way as I explained in the previous video please do get run on different threads and the more processes you have these are gonna get run in parallel Hey so in our startup what we can do is we can go into tasks and call wait oh and for wait'll we would provide an array of tasks that we want to start so we would kick off a couple of tasks so let's go ahead and grab our collect tasks and again this is probably gonna need to be static okay we will put a semicolon here let's go ahead and call this static - and we'll create a process loop as well so we're gonna have two loops running side by side again I'm not gonna execute this code this is just a theory and this does have a message don't really need this message here let's say that it's gonna communicate through other means doesn't matter at this but if we want to kick off these two loops we just go ahead and create a new array with collect and process and these two loops are going to be running now side by side until both of them finish but because we put them into loops they're never gonna get finished and what can be done further as we can put them in try catches and if they break resume execution right but at this point it's an implementation detail one point it is is that when all of these tasks are finished your application finishes and it sort of exits okay the finishes stops now it no longer runs okay this is what you would do with the waiting on old tests now let's say you have this as a task and this is no longer something that you want to return so because this is going to be blocking execution right let's go ahead and create a task that's going to be awaiting on a collection of tasks right and now we want to use when all all right so this is gonna be returning a task but what we're gonna be supplying to it is this and now since we returned a task the way we would actually start the app because if we execute this now it's just gonna finish straightaway right and all the background threads are gonna be filled as well what we want is to actually get the waiter here and get resolved so this is how we would start the app load up a this and comment out the older version so this is how we would start this app in this case but do keep in mind this is still something that we can await on all right so there are your two options to really execute different tasks and you can and let's say you have your two main tasks you can run on the foreground thread and then you have some kind of notification task that might send some modifications and primarily what I wanted to say is let's say when we process messages if we do run into a condition when we want to notify someone we don't really care when that task completes we just want to complete it okay so let's go ahead and say that we want to notify okay and again you need to be static go ahead and say hi okay so a simple message and this is a fire-and-forget one thing to note if you have kicked off some fire-and-forget tasks and your application crashes so you get past this point in your application finishes any fire-and-forget tasks that haven't finished are going to be canceled off and they're not actually going to be finished so you could do something like store these tasks in a list somewhere or a stack so once they're finished you pop them back off in case your application does crash you can await on them after here in your main as well okay again this is more of an implementation detail all that I want to showcase here is an important piece of functionality where we can await on multiple tasks by blocking and this is okay and this blocking is okay as long as it's in the main and it is used as a root of your propagation okay of the tasks and then again just being able to await on multiple tasks and synchronously right so this still returns a task that we can await on and the fire-and-forget function so that's pretty much all that I wanted to showcase here so in this example we're going to take a look at a WPF up and primarily what I want to take a look at is this configure await false example okay and where the main thread begins and where it met the main thread and its kind of thing I mean not by the main thread I mean the UI thread okay so what I want to do is I want to just go ahead and add a button all right anywhere on there can I make it bigger bigger of the button I don't I never really use WPF I just know that this example can be shown through it next thing I want a Xbox and let's go ahead and for this textbox I'm gonna give it a name just so we can grab it and what should we call it test box we'll call it test box so double click on this button I'm gonna get a little function here basically what will happen if I click on this function to my surprise when I looked up how to do asynchronous tasks it's basically the only way to do it is by turning async Boyd on these buttons and what I want to do is primarily how I did in my previous video is just log the thread ID that I'm using while executing this task so let's go ahead and make a private list of strings so this is like my what's it called thread log and this is going to be a new list of string so when I click on the button of what I want to do is I want to log that I am going to be doing step one and that their current the read managed ID will be a certain ID okay so once that's done let's go ahead and grab the next step where we're gonna do some asynchronous operation so we can go ahead and get some content from the internet again I can just go ahead and make a private HTTP client and so when you HTTP client ok and just really simple client get string async and we're gonna call google.com and this is the part where I'm actually gonna run the code in order to see this and then we're gonna help little world here so again this is just an example we just want to see what will happen and at different points where we use configure await okay so then we're gonna use this thread log we're gonna thread log here this is going step two because we're gonna grab some text from this new function and we're gonna make sure we're waiting on it to propagate the control all the thread hey this is gonna be step four because another place that I want to log is right after we get the content this is gonna be step three so we're gonna do step one step two step three then step four is we're waiting here and what I want to do is then I want to grab my test box I'm gonna grab the text and I just want to set the text here so when I run the application all its gonna do is gonna it's gonna fetch something from the internet and it's just going to append to the text of a world instead of text box here now what I will also do is that let's grab another button put it here and this will be our log inspection button right advanced cup advanced concept here but we're gonna add another event and all I'm gonna do here is I'm gonna say give me my thread log buddy and I'm gonna put a breakpoint here just so I can inspect it right so let's go ahead and run this looks like I got an error let's see what's up so I have build errors in a different application okay so I want to run my WPF up up my web app so wondering where they're coming from hey here's the text box when I press this button is gonna turn to hello world and populate the spread log so let's go ahead press it we have the hello world here go ahead press this button and we're gonna hit this break point where we can look at a thread lock so all the steps are executed on the same thread okay and that's the UI thread so it's read one to the UI thread right so basically we're in the previous video you would see the example of the thread is basically gone off and done something else and this has been done by a different task right because you gotta understand that the thread is constantly flooring by riri rendering the UI of the application here what we can do because this task is not necessarily returning to the UI thread so what we can do here is we can actually configure it to false hey so here you will be able to see what exactly it's doing so let's go ahead press the button we'll take a look at the log now and you will see that step number three is now executed on a different thread and again this is not so important for the web application this is more important for the WPF application but again because when you're building a library you don't want to be running your tasks on the UI thread you want to be implementing configure await false okay so your library doesn't work worse on WPF applications then it's doing on the web applications okay so this is only really useful if you're implementing library so again just to sum up is that the configure await is going to run this on a different thread and once we return by stop this term all these windows the step three is ran on a different thread and once it gets joined up back on button click we are since the thread that is going to interact with the UI here here with the textbox it needs to be the same thread okay so this is again step four exec secured on the first thread let's go ahead and see if we try to configure eight pulse here what do you think will happen right go ahead and run this button and Oh exception the calling thread cannot access this object because he different whatever hey see if we can take a look at this thread ad here oh it's over no will it well let let me there away okay so we can see that the execution actually resumed on thread number 11 as well thread number 11 doesn't have access to the UI so the application will crash there because UI runs on the thread 1 and that's where its status kept so it read number 11 doesn't know anything about the UI so that's pretty much just summing up and configure of eight and probably the only place where async Boyd should be used well this will be it for this episode thanks for watching if you enjoyed it leave a like subscribe if you have any questions leave a comment if you have any other specific situations that you have used async/await tasks and I haven't covered it please go ahead and leave a comment under the knowledge I also stream on Sundays on Wednesdays and if you want updates for that join my discord channel all the links that are in the description hopefully I'll see you my other videos
Info
Channel: Raw Coding
Views: 30,092
Rating: 4.9236279 out of 5
Keywords: c#, asp.net core, tutorial, c# tutorial, asp.net core tutorial, async, await, task, asynchronous, explained, how to, use, how, works
Id: 3GhKdDCvtKE
Channel Id: undefined
Length: 29min 45sec (1785 seconds)
Published: Sun Apr 19 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.