JeremyBytes - Task and Await in C# - Part 1: Consuming Asynchronous Methods

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this is Jeremy Clarke of Jeremy bytes calm and today we're going to start a new series about tasks and await in c-sharp we're going to be focusing on consuming asynchronous methods and this way we can get comfortable with how things work and this will get us prepared so that we can start writing our own asynchronous methods in the future so let's just review a little bit of history we've had several different asynchronous patterns in the past and some of these were easier to use than others and some are more powerful than others we started out with the asynchronous programming model or a p.m. this was method based and we usually had pairs of methods such as begin get data and end get data and then in order to tie these together we would use this is Inc result unfortunately this was a little difficult to work with but then things got a little bit easier we had the event asynchronous pattern or EAP this was method and event based and the advantage of this is if you could hook up an event handler you could use this pattern pretty easily so generally there's a method such as get data async that would kick off our asynchronous process and then we would have an event that we would hook up to when that process was finished and if we needed any data out of that process it would come back in the event arts from that event handler now this was easy to use but it was pretty limited in what we could do with it so then we got the task asynchronous pattern or T AP as you can imagine this is task based and generally the way this works is that we have a method that uses a task as a return value so here we have a method called get data async and it actually returns us a task now what is a task well a task represents a concurrent operation what's important to understand is this may or may not happen on a separate thread now the examples we'll be looking at today will be on a separate thread and we'll be able to see that when we run our application now what makes this pattern great is the extreme flexibility that we get with this we can chain tasks together we can combine them into single operations we can have a parent task spawn multiple child tasks so this will work with pretty much anything that we need to do with asynchronous programming so let's head over to our code and see how we can consume a method that uses the task asynchronous pattern so here we are in Visual Studio and we have a fairly simple application setup well I say simple but there is kind of a complex infrastructure behind it I want to consume some asynchronous methods so I have some services in place that will make it easier to do that let's start by running our application now here we see we have a fairly simple UI we have a fetch data with tasks button a fetch data with a wait button and a clear data button and then on the right hand side we have our list box and right now these buttons don't have any effect at all so let's go to our library and take a look at the asynchronous method that we're going to consume for that we'll look at our person repository class and in this case we'll be using the get method now notice the get method does return a task in fact it returns a task of list of person this is one of the things that makes tasks interesting to deal with we often end up with nested generic types but all this is saying is that eventually we will get a list of person back from this task and if we take a look at our person object we see that it's a very simple class and just has five properties an ID a first name a last name a start date and a rating and we also have an override of the to string method now the contents of this particular method itself aren't important one thing I want to point out is this a weight task delay 3000 what this will do is pause operation for 3 seconds this works very similar to a thread dot sleep but the difference is thread dot sleep will block the current thread while task delay does not and again the rest of this method isn't important at this point what we're doing is calling into a web api service so let's go to our application where we can actually consume this get method for that I'm just going to look at the code behind of our main form now I am keeping things simple here so that we can focus on the asynchronous aspects of this application but normally I would split things out between my presentation layer and my UI layer what we see now is that I do have some event handler setup for buttons the fetch with tasks button underscore click and our fetch with wait button underscore click another thing to note is I do have a class level field for our person repository so this is how we can access that get method that we just looked at so let's go ahead and start exploring our code so for this I'm going to say repository git and take a look at what we get back from this method now we know we do have a return value from this so I'm going to start out simple and just save our result equals repository get then I'm going to let Visual Studio help me out a little bit if we hover over VAR what we see is this does return a task of T result and if we look we see that T result is actually a list of person so result is in fact a task of list of person to try to make things a little clearer I won't use var and we'll go ahead and say task of list of person here and I'll go ahead and change the name of result to people tasks so this represents a task that will return us a list of person objects once it completes now at this point you might be tempted to do something like people task dot result if we look at what result is we see that it represents the list of person now it's very tempting to use this directly but the problem is if we call people task dot result this will stop processing on this thread until that result returns and what that will do is it will lock up our UI so instead of accessing this directly what I want to do is I want to set up what's known as a continuation so I'll say people tasks dot continue with and what this means is that after my task is done processing I want it to perform another action and in fact if we look at the parameters for this we can see that the primary one is an action of task of list of person and this is where some people will turn around and run the other way but this actually isn't that difficult an action is a built-in delegate type and all it does is it represents a method that returns void now the generic type on this action which happens to be task of list of person that's the parameter that's coming into this method if you want some more information on elegance I do have a video series on c-sharp delegates and you can learn all about action and funk in there but let's go ahead and create a method for this so again this will return void and we'll call this populate list box since that's what we'll be doing inside this method and again the parameter that we need for this is a task of list of person and I'll go ahead and just call this T for right now for task and now that I have this method signature in place I can go ahead and put this into the parameter of our continue with method now I do need to get to the list of person that's inside of our task so I'll say t dot result now I know I told you not to use task dot result earlier but here it's actually safe because this is being called with the continue with that means this method will not be run until after that first task has completed that means the result property will be populated and we can use it safely now there are a few exceptions to that such as if the process is canceled or we get an exception during that process but we'll be exploring those in later videos so again T dot result is a list of person so let's go ahead and just create a variable for that so we'll just create a list of person called people and we'll set that equal to T dot result now we can just use that variable to populate a list box so we'll just say for each var person and people person list box items add person so we'll just loop through each of the items in our collection and add them to our list box so now that we have this in place it seems like our application should work so let's go ahead and run our application and then click on our fetch data with tasks button now again we do have to wait three seconds for that delay to come back and what we see is we actually get an exception at this point and let's take a closer look at what the exception says the calling thread cannot access this object because a different thread owns it now this will look familiar to anyone who's done threading on their own what we have is a situation where we're on one thread and we really need to be on a different one now the reason for that is that when we create the task again in this case it actually creates a separate thread different from our UI thread and when we do our continuation it will continue to operate on that same thread now inside our continuation we are trying to access a UI element our person list box but that's owned by the UI thread not the thread that we're on so in the old days what we would do is use dispatcher dot invoke in order to marshal this process across the threads but that's something we definitely don't want to do today so let's see what we can do to fix this so we'll just stop debugging and you might have noticed when we looked at continued with it has a number of overloads for tea in fact that means that there's some options that we can use now I don't want to look through all of these so I'm going to jump ahead I know that we actually want overload number seven and notice what we have here a task scheduler so I'm just going to say task scheduler dot from current synchronization context now let's talk a little bit about what that means what I'm saying here is that when we run the continue with tasks I want it to use the same task scheduler that I'm currently on when I create this continue with now what's the task scheduler that's what figures out when to run the tasks what thread to run them on and so forth now I'm actually calling this continue with method inside the click handler of our button that means that I'm calling this from the UI thread so what I'm specifying is please run this task on the UI thread and with this one change we'll see that our application now behaves the way we expect it to so when I click on the fetch data button we'll wait our three seconds and then we'll see that our list box is populated now I'm someone who loves lambda expressions and whenever I see an action or a func I treat that like a big flashing sign that says put your lambda expression here so I actually want to inline this code so I'm going to copy the parameters and the method body of our method and then up here instead of saying populate list box I'm going to paste and then in between the parameters and the method body I'm going to add our goes to operator that turns this into a lambda expression and let's just indent things a little bit here to line things up so now I have a lambda expression that takes a task of list a person as a parameter and then performs the action that we specify by populating our list box now I do like the syntactic sugar that we get with lambda expressions and one of those is parameter type inference which means if the compiler can figure out the type of the parameter I don't have to put it in there in addition if I only have one parameter I don't need parentheses around it now what's great about this is our parameter T is still strongly typed so we can see it is a task of list of person but the compiler can figure that out based on where we're using this so we don't have to type it in explicitly and if we run our application will see that it behaves exactly the same way it does before and just to show that the UI thread isn't being blocked after I click the button I'm going to move our UI around so we can see our UI is still responsive in that intermediate period before our task actually returns and then back in our code since we have our lambda expression I can get rid of this separate method that we created earlier so this shows how we can interact with the task to take full control over this asynchronous process but we can do this with much simpler syntax now and for that we use the async and await keywords let's take a quick look at those so you might have seen a sink and a weight in different methods in code what this does is it creates a syntactic wrapper around the task so that we don't have to go through quite as much ceremony when we're using this when we write the code using a sink and a weight it looks like we're writing synchronous code but in fact once we hit the awake keyword our method will pause until the task completes and the great thing about this is even though it looks like a blocking operation it does not block our current thread now you might be wondering about the async keyword this is really just a hint to the compiler if we write async on our method it doesn't magically make our method asynchronous what this does instead is it tells the compiler how to treat the await keyword now the reason we have this is a weight is a new keyword that was added to the c-sharp language and we don't want to break any existing code so if we don't have a sync then a weight will be treated just like any other identifier that we use in the language but if we add async to the method then a weight will be treated so that it becomes this asynchronous process that we want to use here so let's head back to the code and take a look at how we can use this and for this we'll fill in our other event handler fetch with a wait button underscore click now the reason I kept these as two separate buttons is so that we can compare the code once we're finished with this so again we want to use repository get but this time let's take a closer look at what visual studio is telling us here so this does tell us that it returns a task of list a person like we saw before but notice that this is also tagged as a way table and in fact it gives us the usage below so list of person x equals a weight get so let's go ahead and try this we'll start by creating a variable for the return type which will be called people and then we'll use the await keyword now notice visual studio is not happy with us at this point and if we take a look at the error message it says the await operator can only be used within an async method and then it tells us exactly what we need to do consider marking this method with the async modifier and changing its return type to task now I won't be talking about the return types in this video but we'll be looking at that in future episodes for now we'll just say private async void and when we do that notice that the await keyword lights up and our red squigglies go away and if we look at the type for our people variable we'll see it as a list of T and that T is in fact a person object so again let's be a little more clear and just say list a person in this case so now that we have our list of person let's just use it like we did before so we'll for each of our person in people and then we'll say person list box items add person and when we look at this code it looks like synchronous code so we call clear list box then we call repository get put its value into the people variable and then we just for each over that and put it into our list box but that a weight keyword makes all the difference in the world let's go ahead and run our application and when I click on fetch data with a weight again we'll have to wait those three seconds that we have delayed and then we see that our list box is populated and just like with our tasks in that interim period our UI does still stay responsive so we do see this is running asynchronously so we have two different ways of getting the same results we can use the tasks directly and take full control over the continuation or we can use the await keyword and let the compiler handle things for us as we can see using the await syntax is much much easier and in fact we didn't have to worry about the task scheduler or what thread we were on either now you may be wondering why I spent so much time talking about tasks when there's an easier way of doing it and the reason is that a wait will not fulfill all of our needs there are situations where we'll want to take more control over the process for example we may want to have multiple child tasks that all run at the same time or we may just want a little more control over the cancellation process the main reason I show it is because the first time we see async in a way it really looks like magic if we don't understand what's going on behind the scenes then we might be tempted to simply sprinkle a sink and a way throughout our code and just hope that everything works right but if we have a good understanding that behind this is a task and it has certain context that it runs in then we have a better chance of coming up with a fix if something goes wrong and that's the basics of consuming asynchronous methods with either task or async/await now in future episodes we will be looking at some more details of this including additional functionality such as how to handle exceptions and how to do cancellation with an asynchronous process until then be sure to follow the links in the video notes and that will take you to the code samples as well as a series of articles on this topic and of course for more information be sure to visit www.mptv.org/outdoorwisconsin
Info
Channel: Jeremy Clark
Views: 48,833
Rating: undefined out of 5
Keywords: Await, C# (Programming Language), Programming Language (Software Genre), Task, Asynchronous Programming
Id: 0qiB3oW_nd8
Channel Id: undefined
Length: 18min 22sec (1102 seconds)
Published: Mon Aug 31 2015
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.