C# Tasks Async Await

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] so in this video we're finally going to talk about tasks and a weight and async the kind of the key thing in c-sharp for doing any any task work which basically means when you see say a public and a function that returns a task and you know do work and then typically a task would have an async and inside it would await something you'd have something similar to that so this kind of this set up this task set up so that's what we're going to talk about in this video now I'm gonna try and keep it sectioned and organized and most of it will be explanations more so than code will object to code examples but there's also going to be a lot of conversation going on about what you know what things are and so you can fully understand tasks so I've done the previous two videos on threads so hopefully you understand multi-threading now which is very important for tasks and you know how tasks work because ultimately you know they make heavy use of threads so hopefully you're gonna you know understand that concept so the first thing we want to talk about is firstly what is asynchronous what does the word actually mean so the word asynchronous basically means if you start something and you don't wait while it's happening you don't wait for it to finish and it literally means to not occur at the same time so that's what you know asynchronous actually means as opposed to synchronous which means everything happens and waits for the the previous action to complete before it moves on so asynchronous basically means that it doesn't mean that our code returns early but rather it simply doesn't sit there blocking the code while it waits so it doesn't block a thread talking from a code standpoint so I'll dump that kind of description in here as we go and I'll share this this as part of this video because it's gonna be a lot of descriptions at least you can kind of read through a project as you go so that's issue one if you will or rather topic one which is you know what is asynchronous the next topic is going to be the issue with using threads because we know threads are asynchronous so you know we're describing what a synchronous is but we're talking about tasks so now it's a case of well we can do asynchronous work with threads so why don't we what's the issue with threats and so firstly why are threads asynchronous we've described asynchronous and I'm saying they are so let's break it down and describe why so threads are asynchronous as they naturally do something while the calling thread that made them doesn't wait for it so we can show that with a code example so we first come my little stamen there and now we'll do a code example so I really console.writeline before first thread and we do another one so after first thread I get rid of that return here and then in here we do new thread and inside the thread we then start we simply say inside first thread and let's do in order to separate this up to show this we want to show that this doesn't wait for this so we'll put a simple thread sleep here oh say 500 milliseconds and then in order to clear off for the next example after this fight will do a thread sleep of like a second just to make sure that anything that we do after this point this doesn't come in afterwards so if we were to run that example and hopefully this is gonna open up on the right screen but it never seems to open up on the right screen and of course it doesn't and let me just put a console realign so it doesn't close put a breakpoint laughter keep doing the same thing you did in the last video until I fix this issue so the window keeps opening on my second screen so here's the the window and this is gonna be really annoying let me see if I can fix this again okay so if we run this example you can see we get hello world before first line after first line and then inside thread which means that the order has gone here to here and this is you know ran independently which we discussed in the the thread video so that is why threads are asynchronous and because they run you know there or rather the caller doesn't wait for the the action itself to run which is what we've described above so that describes why threads are asynchronous so now it's you know what's the issue with them so the first issue is doing this doing a new thread is an expensive operation creating a thread consumes memory on the heap it consumes Ram it consumes process you know it takes maybe almost a megabyte of RAM to keep a thread in in memory and to keep to hold state and it also bogs down the system that has to switch between threads the more threads there are even if they're not being used it has to evaluate every thread to find out which ones available so threads are an expensive operation you know typically ones making a new thread for every little operation that's as you want issue two is it's not natural to be able to resume after this threat is finished back here if you will without blocking this thread so it's it's not a natural way in an easy way that we want to single nice clean one line to say do this work here on a separate thread but then carry on here cuz that's how we look at code we want to see it line by line and understand it line by line so threads are not unnatural you know they're not very natural at being able to be useful in an asynchronous will the way you want to await them you know you want to wait for something to happen so let me just Chuck those two issues into the description so you can you know like say keep an eye on Ford with this let me just Chuck this description here and now we'll work on issue one as expensive to make so the way this was solved is that they created something called a thread pool and a thread pool simply is used to cue worker items so if we do thread pool a your cue new worker item so this is then you can you know spin up an object to do some work and all that does is it goes in and that there's no threads that have ever been used it does a new threat because we need the thread but then once this works finished the thread pool keeps hold of that thread for a little while or until it determines it's it's using too much memory and it cleans it up but what the thread pool then ultimately does is keeps a living pool you know living collection of threads that can be consumed by anyone wanting to do work so it's like you run say you run three operations and the second operation starts a second after so this threat has since finished and instead of it being disposed and then creating a brand new thread it gets recycled and reused because it's since become idle so the thread pool solves issue one however issue two is still an issue for threads and there's no real clean and easy way to do this and that's you know why tasks were made so in order to resume work after some asynchronous operation has occurred in a thread then there's a few options that people have done for years obviously until tasks are about and one would be to simply block the calling code so you know block this with a something similar to this so in fact let me do an example in codes let me just first again take what we've described and dump it in and we will do some code example so I've I just paste this in here and we want to talk about specifically what happened here so if we were to plot the thread we would have to do a new thread and we would do the bar block but as a new threat inside blocking threat and we don't start it straight away as we want the threat then you can be a blocking thread start and the way that we block your code to wait we do basically blocking thread join and this is one way of doing they're the solution if you will so this would now be after blocking thread and we do before blocking thread and hopefully these kind of examples are gonna be useful because then you can simply run them all and you've got a single single code file to kind of see what's going on so we'll have the first inside and before and then here now you've got before the block in thread and you see inside block in thread and after block in thread so it's it's literally blocked our thread in it in an inefficient way so this thread is no longer this thread that were on there's no longer of any use because it's while it's waiting for this thread it's effectively fully blocked so this is no almost a completely pointless piece of code because all you've done now is created a second thread but consumed two full threads to do one piece of work that could have been done on one thread in the first place so this is effectively not really a solution in any sense it's completely useless so that's obviously not a solution the second way of doing it is to constantly pull for completion while waiting for you know say a flag to be set in a loop and this has the same kind of issues because there's so many ways of doing it and there's not necessarily the way you would do it as the way I'll show you but to get the point across it's it's exactly the same and let me in fact wrap the code samples up so the comments are clean so there's issues or are there threads are asynchronous there we go and we'll wrap this bit in and then we've got code samples and kind of embedded in the comments so it's nice and clean so blocking thread or blocking wait let's call it and that will go to here and then in order to do the call back style like constantly Pauline so we'll say before Pauline thread and like I say there's many way to do this this is not necessarily how it was done but it simply proves they're the exact same point of the fact that it's inefficient anyway no matter what you did yet you still effectively locked for the most part into the thread so this would say Paul inside polling thread and then we would start and this time we don't join so now instead Paul for completion so you basically do while well one way we could do it is we'd have for Paul complete it goes false and then once we're done say Pauline thread complete or rather we don't need to say it there we can just do it or complete people's true set complete and again there's many ways of doing this you might want to use a tough well not necessarily a task completion so uh spot you know reset events or timers or anything but again that's not important in this sort of description is simply showing the point of one way it might happen so you could say well I'm not Paul complete so we know while it's still running you can do say thread got sleep through anything you don't necessarily have to do that dot sleep and you're sitting you can tap old for you know this permanent loop and you could do work in here you know some work but in essence you're waiting a set amount of time and if that time was say a second at a time then this could have been finished for half a second before you do things so as many issues with doing this way so this is after Pauline Fred and you could even put if you really want it to be kind of see what's going on and you'd remove this I'll comment this bit out but you could say you know to see it physically happening pop up there say let's just change this to say 50 so doesn't happen that many times you know we were on this example you'll see inside first thread and then you've got Pauline inside Pauline thread there's a bunch of holes and then it's after so it's the same kind of issue yet your threads ultimately stuck whatever you do you're simply pulling for completion you could do a well the next next thing we'll do is an event based callback but this is the way your Polly's literally sit and wait for it so it's change that to just a hundred so we can leave it in the example actually so it keeps it clean so that's a second way of trying to you know solve this issue of waiting for it to complete and them resuming on the thread that we want to do work on and as I mentioned there's the issues with that so the third step is well the third way can I solve this is event based call box so this is very similar to polling in one sense but this is going to introduce something else into the mix which we'll see in a minute so we are we been based waiting so this before event thread we don't need that this would be event thread inside event thread doing something and then by a completed event now this would obviously be done slightly different but again for the point of example it doesn't really matter this should be after event thread and now here we need to make an event to fire so by default we'd have typically you know you don't an object to a class or something that you register to you and necessarily start a thread this would be a class that maybe contains a run action that does a thread or you know again the point is the only point the matters as the way in which we do you know the point of event based call back what happens in the call back when something is wrong so the simplest way I can show that is to make an event directly so let's just go up to the top here and just do private static event which does nothing just an action do event finished and create a blank events or not after new it up and then also we can do in here and again like I said this is not how it would be done necessarily but it proves the point we were before the event starts you typically create the thread that usually hold the event or create a class all the events and then we begin to event so you'd say and again like I said this is not how it would be done but kind of shows what had happened it's the exact same principle you're listening on the event so we'd have event finished plus equals and then this is our now call back if you will so pull back from thread and then in here we'll just chalk in that is rather at the event that this is he went web called pull back on completely to show that this is what happens once it's done so then he a fire completed event would be literally to say if the events finished you know you inform any listeners of the event so what's happening here is we create a new thread we hook into an event that's right now not necessarily linked to this doesn't really matter we hook into greater threat whip into an event we start the thread and then we state that we're now here so our code will run there to there hook into here run those two lines in and up here once it hits here's all step through to show you that then that's this thread done and waiting of your well hits now this threads idle waiting here about Queen then this thread runs in parallel and starts doing this work so we'll go inside the thread it'll wait and then it'll finally go fire off an event and then because we're listening here this event will cause us to hook into here and end up firing this call here so what you should see is before event after event and then you were inside event and then the callback and I'll show you the kind of stepping through and code just to let you see that so we go before he went the threads ready we hooked in we start the thread and it's after and now we're at the read line and then you can see if we rerun that now without breakpoints just so you can see it happening directly so you have the before event thread after you been thread once you mentioned now that threads fully done then you're inside the event thread and the event thread callback on complete so you can kind of see that happening so that's one way of doing it and you can then encapsulate this into sort of a function so if we were to do say a priori static void event the read callback method and you could just have event or I can even have an action completed and do a callback in this fashion then this would do the same work as this thread so we do nothing different in essence here we just simply do a inside event thread method and we wait and then we fire the completed events then we say completed so this is another way of doing the exact same thing so if everybody's wait and copy and paste event based way method and then this way before event method thread and then you wouldn't have any of this because it's now a method that contains all the work we'd simply say event thread method callback and your callback is now in here like this so that's the the hook if you will is by passing in a lambda action to you know call back so didn't nothing different we simply moved the logic into a method and this is weighted then look like and so if we run that code we'll see exactly the same action happening no different apart from we tried to start a thread that we didn't create a line of code in that so you can see then you've got the before event thread after and then you can see also before he went method enough inside inside event fed oh I know what we haven't done we should also wait as I mentioned once we're doing anything that kind of holds and waits let's Chuck a second delay to like that clear off so we don't get this kind of cross-contamination of things happening and also I should probably choke in like a nice long thing on the befores and afters or rather just on the after so that we have a nice separation to visually see the difference in all these examples so let me just Chuck this line of code every time we do an after and this one will also want the nice driver noticed that asleep after the fact again to get past that so now if we when we should up slap the clear output so there's the blocking example there's the pollen example there's before and after the event thread and in fact we should move that sleep inside so that the layout stays correct that one we also haven't waited for for some reason okra pollen we don't need to wait for that one as a block and we don't need to wait for so it was just that one mainly and this one and then we should have a nice clean separation of what's happening where now you can now see the order nice and easy so before we got the thread after the event thread inside and then call back and then before in this case we've got inside event thread and after so I've actually got something different going on here which is obviously because I've done this wrong it's not what we do this it typically be a task or rather a threat so as you mentioned it's kind of sharing the same example here of what I was doing and that is just to you know start a new thread up I just I was moving the logic inside a function so it would learn to be that which now should give us the same result they see before after inside callback before after inside callback so these two are the same just ones done in a method than the other ones done directly in line to show you the point so in order to see though the issue with what's going on here we have a slide to do here where we change threads which is important when you in like UI applications so there's a significant change here in what's happened with the thing the action that's running because in the polling and the blocking you're physically on the same thread and when you finished you resume on the same focus you've never gone off it with the event based callbacks but the callback has happening here on a different thread so it's not really obvious until we start logging some output with showing threads so let me just chuck in a helper so private static void log and then we'll have the message and then we're gonna have the console.writeline message but we also want to output the current thread run so we can see so the current thread will simply put in a little square brackets onto thread common thread manage thread ID and this will output I'll put a message with the comment thread ID appended and I should also comment these codes I know it's an example but this is a usual examples you want to comment everything shows an event-based thread pull back by a method call back to full wants the method is complete all ones the work is complete more specifically start the new thread log it so now all these will change to log instead of this so we get the output inside sleep and then fire event complete it's that's that I'm happy with now we've got comments everywhere in here you want to change to log so we'll you can change the hello world to log to get the output say log it threads an asynchronous log or wait for work to finish that one is really so I will log this will log this will start a new thread sleep a little log it log after wait so that's just showing threads asynchronous the blocking call the log create you that this time sleep a little start that block and wait block and the only difference here is we don't need to log the dot dot when I mean over don't really care where that this happens this is purely for splitting up the areas cleanly so this runs log again [Music] create whole flag create thread sleep a little and then set like complete start thread pol for completion blog while we're waiting sleep a little they only done now two more left and then this will show you the output now which will start introducing the you know what's threat drawing we can start thinking about things as in a true multi-threaded application I'm really getting a heads around what's happening in the difference event took ten core bar and then what did we write for the last one that kinda waited and linger was a Hollen warning bambe sworn that's the first time I thought we did Donna wait for work to be completed how that was up here wait for work to finish we said so over there wait work to finish and event based last one should I just comment it up the staff so I'm going to go back Rosh Hashanah talk through examples to get it going so poor method and then the callback is here we also log and then we said what was it wait for work to finish that okay and so now the only difference here is we should see the current thread where everything is running up which is now useful for us explaining things let's go back and just explain a few things we've done this in the last video explaining threads as who she'll be obvious so you main thread when you start your console is that I do want and then you can see everywhere where it's running on thread one that and you can get a view for that so in terms of the code we we don't need to step through all of this we've done it were before and after the first of ed and then we know this this other thread runs on its own thread ID it's a new thread and that's that's what it says we know that and then we get to the blocking thread which is in fact the first that needs a separation first thread and block in threaded two separate things so that needs a separation there so the first example simply shows that the after again put that before the the sleep not after so the first one is showing simply synchronicity which is before and after the thread is that one thread one link carries on he ultimately but on a separate thread this gets run then the blocking shows that this gets called then we wait for thread for to complete then we carry on the pollen shows a similar thing we start on thread one weed pollen thread one while thread five starts running the work and we sit there falling then when finished we're on thread one so ultimately what we're noticing here is after the work done or are that when the work is complete they think we want to run after works complete so far as thread one so that one we simply didn't wait their thread one and then we move now onto the event based and you'll see the difference so now in the event based before and after the thread or med one then the thread starts running but now the callback when the works complete importantly has actually run on the same thread as the the action that the method that was being run asynchronously so the once we've finished working on this thread in an event based callback it means that our callback thread that we might expect to be on the same thread for example in UI if you want to wait for an action to complete and then set some text in a text box you're going to be coming back on the wrong thread you're not resuming back on thread one so this is the key important difference with event based callback and you needed to understand you need to once see that happening and to understand if you watch the last videos about threads and the UI thread why you have to be on the UI thread to change you know UI elements so this is a important issue if you will at least an important style or thing that happens for the event based callbacks we now lose the calling thread that's kind of a the issue that you also got issue with this issue with this issue with this and what we're trying to show here is why tasks were created so I know we're still on threads at the minute and I'm sure you eager to get to tasks but it's also important to understand why tasks were made and why threads aren't suited for it - what issues you get with using threads as opposed to tasks so the last one while the latin to be honest the last issue I had was function callbacks which really is what this is so real is only three ways of doing it as most common ones are three ways of doing it because this is the same thing I've just styled it slightly different so obviously what this also means is that every time you want to do and another issue rather with say this event based I'll call back where let's take the method one it's a bit cleaner say now once we've called back and then here we want to do something else whatever the thing we want to do as a call back what you then end up with is other thing I wanted to do as I pull back and I'll do something in here another thing I want to do with that as a pull back and what you start getting is these nested callbacks when you code ends up getting deeper and deeper and deeper into a nest which is not what you want you want to try and avoid the nesting situation so lose-lose context calling that on call back and cause is nesting so that's that's what will comment there so this is a whole wall is issues with threads let's also make this a little bit clearer with titles and I want this to be as much a document as it is a piece of code so like I say you can pick this up read through and understand the principles so basically the other issue or rather the issue overall with these threads as you can see is basically however you make the way of getting a call back to do something after something's awaited there's a lot of code or there's a lot of like workarounds or non clean code and that's ultimately the issue so if I just dump a little statement in as a finishing statement of kind of you know where the issue is with thread and that's really the main issue with threats so this necklace really brings us on to what is a task I guess so if we just copy the tile paste it in here change this to autumn tasks also notice that needs an extra bit there there we go so what does a task so basically a task is any simply to online they don't want to describe it in one line I don't want to make it confusing because it isn't a task encapsulates the promise that an operation will complete in the future which is ultimately what all this is about so a task is defined in that worry too because a task is an object that we return so it's a physical object we can make use of the object itself is the promise of work to be completed in the future so we're returning not necessarily a thread we're returning and objects as representing that a piece of work will be complete in the future and we can subscribe to a wait for that to complete and resume so that's ultimately what a task object isn't it as a true object and just get returned so tasks and catch relates the promise I'll actually slower at typing what I'm talking promise of an operation completing in the future and that's all there is to it that's all we're gonna say about two tasks that's what a task is it's that all bring us on to the tasks async and await keywords which I think will be not necessarily oh yeah it's its own header I guess so this would be tasks async and the wait and in here then we can start our I will work on async so async in c-sharp has mainly two words so those words are async and await and the point is to allow easy and clean a clean asynchronous code to be written without complex and messy code so basically it's to do what we've done here and in all these examples in a more efficient and code clean way so you don't have to write all this boilerplate code so that's the point of you know this if you will so let's see this in action we want to see basically what synchronous code looks like compared to asynchronous so it's time to actually see the word async and await an action so the simplest example I can find or rather I can think of if we make these are methods calm time very well today this is where helpers that's not really helpers it's thread methods we just simply using in a thread section and now we'll have tasks example methods so the simplest thing I can think of to show an example is let's say we'll call it web download string and we'll pass in a nail download a string from a website L [Music] sync synchronously there we go down to download that's just a normal function that you've seen before and this is a sync pattern you know a synchronous pattern and for that we'll just do VAR web client equals new or client or do nothing new here that you haven't done this is not asynchronous this is showing how it was originally done so we'd have a result equals the web client download string and then we pass in the Ale and then we can log out the well we could lock out the result but to be honest we want to log out the whole result we'll just log out some of it so we'll log downloaded Earl and then we'll just output result dot sub screen we'll always presume for this example that we have 10 characters say I'm not really bothered about this example not crashing it's you know we shouldn't not crash it so let's first make use of this web download string so we will have here I guess what should we call this a hmm sink vs. async method I want this web download string can will do our website equals google doc coat UK and we'll pass in website to fetch download the string and let's just run that for now and see that should happen and download and output what we're hoping is 10 characters so there we go we can see it's got some file so when we look how about it's got a string you can inspect if you want to see the whole string you could just put a breakpoint there and inspect its you know or to you we should also just for quickness in this example let's also do private remembers the event finish callback for the credit event example now I'm gonna do some settings so privates started boolean run throughout examples and this is just for quickness so now I can jump into each of these and wrap it to say you know to be honest I could kind of wrap the entire thing save doing it inside each of these threads but it's it's gonna make the all the comments out of line and start indenting so for the actual a bit of work I'm just gonna do it for each one so run thread examples I'm going to go to there copy that fit then you should go to the bottom and indent and I'm gonna do that for each one so bear with me while I quickly do that and it just means that we don't have to sit and wait for all of these examples to run us work working through this we don't want to wait for you know five seconds every time I run something to see finally when we get to the examples we're talking about and then you can just turn them all on as on when you want to run them and it's nice and clean there we go so now we're illness we should get straight into our example here which is downloading Google so we also got to put in the the logs that we do to keep things the same so before sync versus the async thread or rather before sync thread because then we'll do one before the async one and then again you'll see the results here so that's no different than running anything synchronously so now there's the asynchronous call which will finally make use of the async and await words so we'll do private static will also do avoid right now we're not going to bother returning anything I'll show you the the actual physical tasks after this I just wanted to show you the the actual code example so to be honest we can copy almost copy all of that and we'll start with that to show you the changes because there's very few genes we can also even copy there a comment and paste that into there like so this is only about a line of difference so this will be web download string will call async because that's the typical naming convention for anything asynchronous is to end the actual name and async now the only difference to do is we tagged before the return type typically we tag the function with async so this is that the key word here async and I can see it's gonna tell us the async likes and await operator because they run you know they expect and a weight and their weight comes when we change this download string function call to a download string async which is already been made for us in the the library and this overloads simply has to have a URI instead of just a string which is a minor change and then the result is in fact what my doing different here so the task async is what they do they've got two of them ones asynchronous in the old style which were not bothered about and then this is the correct one so download string task async if the name we want and I can see if you hover over it's a task which is the first time we'll have seen the task here and it also says in brackets away table so that's a hint that we can await it so at the start of it if we didn't await the results a task which is not what we want or not we don't want to get into task just yet the stead we await the result and now the results back to being simply a string so the key differences here is really with four async here and we've awaited a call that now returns a task of string instead of just a string and they're the only two differences so again this is the whole point of the async and task library of UL in in.net now it's meant to be as little work as possible and as little change to your code so that when you look at this you can naturally understand it in the same way that code comes in here goes to here runs this this now runs on a new thread but effectively you get to here after that fact so you doing what all of these examples are trying to do you try to run something on a new thread here that then carries on here and we can prove that by stepping through line by line so if we just also copy and paste the before async thread after async thread and we do the async call and we run this we'll see that we have before sync and then here we now step through which will of hit were mainly bothered about this so we hit this spins off now the next lines here so we've even step through just like it's synchronous code we haven't magically disappeared off somewhere and come back we have because if you look at the call stack you can see we've actually we're not you know this wasn't the previous line of code so the magics happened for us but in terms of what we visually seen and what we step through what we've understood we've gotten line by line but what it did is actually a lot more complicated and we'll go through that after but in terms of understanding what happened and then appearance-wise it looks like it all happened exactly the same so we have here the exact same behavior so before download after and then here you'll also notice we now got before after download because that's the point of asynchronous it's it's happening without waiting so we're back to now happening and not waiting I think I'll just also put a break between those two lines just to separate them but I don't think they need to be in their own little container that will also we don't know how long that will take so we kind of counterweight that will we kind of wait it but it's not necessarily gonna be accurate if we leave it as this so one other thing I will do is change this voyage now to a task so you can see and nothing changes you'll notice so I change the return type to a task and by default it's returning a task and you might wonder how that is and that is because there's a weight effectively returns so when you're hitting a weight it's actually returning the task at this point and then all magic happens after that which we'll explain so just think of a task as if you await it or you wait anywhere inside the method when you've got a task an async task then you don't need to return because the weight itself is the return I know it's a complicated thing to try and understand but you're not actually having to say return something because a task is like a void it's an asynchronous void almost you can think of it as and as we mentioned in the comments here a task in capital AIT's a promise of an operation to complete in the future which makes sense because we're returning at this point the task and the task is the promise that this codes run first and we've returned and we've returned a task and the task is the promise that this will happen after or rather this will happen after this bit of code is run that's kind of what's happening with that but I just wanted to add that so I could then show you here we can also wait but we can't await directly in here because we are in static void main so you know we have no way to await that as such so I can't do something that I wouldn't recommend doing this specifically but it's okay for this example and we'll talk about it after download the string a synchronously and wait just for example or rather if we do and the only reason I'm waiting us to shoot so whatever we do after this line always runs after that's finished so far download task equals their log after and then here now we want to wait for tasks to complete download task oh wait and now we'll be assured that that dashed line will always happen after the download so even though that's happened then this is happened after we've waited on the task to complete so that's kind of the starter there so this is your first introduction into a sink and a wait and task here this is how the typical functions Luke and I want to go obviously more into depth about that and a few key things as I've mentioned as one if you see async you should not know it's not going to break if you don't do that if you do this and comment out this you know invalid code it's not going to compile and say you can't do its but just gonna warn that saying there's no a wait operator so it's kind of run synchronously so in theory when you see async you should all see a wait the what the other way around though you cannot wait to be don't see a tink you have to have those two impaired so these two you can almost think as a pair the async as a method value it's not don't go into the method signature meaning that if you were to override this function you don't override with async async a compile-time directive that changes the physical method but for what you need to you know worry about you if you see a sink in the method you should see a weight in the the actual method body and 100% of you see a weight here you will see a sink you know in the method so those commas a pair is kind of the the point there and it goes the same for lambda expressions when you create them dynamically and if you were to do VAR a equals you can do a sink and create a dynamic function and a weight you know something here and you can create a function that way and you can't explicitly type you have to tell if it's a just a tasks a can't convert lambda tough because it's well whatever the case that the point is there you know when you're defining them in a function you can simply instead of defining it like this as a lambda you can put a sink and prom Tommy to now your method inside is a synchronous basically so you always see them you know in a pair like this and then the next point which will put these in the comments first as we go so we've kind of shown that and I wanna you know finish off there the comments so a sink and a waiter always used together a method or laundress tight with a sink a methyl on was tagged with a sink and then any task and use a sink to a sufficiently away Tet so that's kind of what we're trying to state so methyl lambda type with a sink right this a bit better and then oh wait any task that's really what we're saying and there we go it's just there the basic statement there so the next thing is when you await something and this is where I'll kind of explain what happens then we'll go into an analogy and then I'll deep dive into what's really happening so when you await something in terms of like here the thread which called the await which is this that fed that we've come in on a thread that called the await is free to return because as I mentioned the function does actually return here and when it compiles it does change and this function really does say return tasks and it returns the task from here and all you know magic stuff happens that will explain but basically the calling the tasks that called this called the await of you well it's free to return and do what it wants to do and then in parallel this function the task inside of you will be await so effectively this this method here whatever it is that comes after the weight on the right side now runs on another thread and once the task is done it returns to here the starts when you work or rather it returns to this line it sets the value to here so the left operator here technically it returns here and then carries on below and where it carries on all depends on the context and what really did depends on the context and the partitioner if you will of tasks which is won't mean anything to you right now but ultimately what happens is you come in on safe thread one here and you go up to this point and then you we get returned the task and now the red one carries on as we've seen does whatever it needs to do which if it's just a thread with no context it basically has no other job so it kind of waits there anyway you know nothing really happens and this then runs on a new thread this action and then when it returns here you'll notice this will end up being on a different thread so if we actually paid attention there what we should see is you notice the in fact have we not awaited that yet oh so we didn't await it so it doesn't change the flow so we were to slightly change this and say let's make one more example because there's a key difference between waiting and are waiting because waiting is a synchronous operation so this time before async await threat so now here we properly await it so we want to wait for that task to finish which we can't because run difference well so we'll have to just do a new thread or rather task we might as well use start using them to show you and I'll explain this one after we spit up on a new thread just so we can do this that start wrong why are we not getting a movie pile timer give me a second away before async await after async await we don't need to wait now if I waited that's the same there but now why not but there we go so now we'll just wait this task so what I'm doing here in order to await because we're in a console app and it's a single-threaded whilst not a single-threaded are actually because we've got a single thread here though study would mean we can't put a Singh here it doesn't let us do that I think it doesn't future if you update to the latest one in fact yeah oh as it laners do it now I see show up updated that to allow it in which case that makes my life easier but I don't think it does not me compile first and check yes I think it's gonna complain that there's no entry point into the application but it's not showing the error for some reason but yeah you can't have a static void main with a sink so what we're having to do is to spin up a new task or rather a new thread in essence make it asynchronous so this is where I was talking about you can make an async method here her lambda expression so we spit up a new task and we wait it you don't need to understand this just yet because we'll explain it in a minute but all that that wrapper here the tasks and the way to simply so that I can do an async inside and show a principle I'm trying to explain so let me run this and then explain what's happened and what's different so you've got your normal one your synchronous that we know how happens you've got your async one the first true one which goes start finish and then this happens separately and now you've got this and this is where you really use async this is how you typically use it you do something you're the way to function you do something else and this happens then this happens then this happens and that's what's happening inside the function here you're doing that then you were waiting that then this happens but I can't show the principle of change in thread because this is a function we haven't written so nothing you know we can't go into that and say well let me know what threads running on can't log anything out so all's I've done to show this principle is just spin upon a new thread and then we output the thread we start on we await some work that outputs that thread it works on and then we see what's after so what that gives us is before async await we're on thread eight now because we should put up a different thread here to do the work but that's not important what's important is the original thread so you can see before we start the work or on thread eight then we call this call here web download and it jumps onto thread five which will also notice has already been used above it's the threads been reused because I've made use of a task here and so the tasks make use of a thread pool so the key difference is we start on one thread then we say await this work and the work happens on leaf and thread but you'll notice even though right here the line after in the line before we're on a different threat we've actually changed threads and that's an important thing in the await and it's similar to the reason why the event base weight method changes to that because the thing firing back and coming back on to to do the work is the thing that's on the new thread so we've said await this work this work goes right I've been told to await so this bits gonna happen on a new thread but then when it has to come back and continue afterwards because remember the function returned here it has to continue the work afterwards it's got no way to get back onto the original thread unless there's a synchronization context to jump back on so what's happening is we're on three different threads and you can see that happening again in the debugger if we breakpoint in you'll see here we've got code we're in an asynchronous method and we're on we do debug window threads you can see right now we're on thread eight it's a worker thread and then we step over that and you see all of a sudden now we're on thread five thread eights down here is not available and we've got 35:31 is waiting for the task es on one thread it's waiting for this third to finish what it's doing but you'll see effectively the threads changed and also the call stacks change to this resume so we know something is going on here we know some magic is going on and that's what you need to understand about tasks is even though it looks like you've done one thing two things three things and you're debugging it goes one two three there's a lot of things that really happen in the background that you should understand so to explain the task it's nice and simple it's you do work and if you choc await in there the thing you were waiting does its work on a separate thread and then calls back and starts working here again but the key thing you need to understand is what's happening in terms of the threads so let me just put this note in the code as always to keep this document updates love-struck I'm in notes in so when you await something the thread which is called the third which called the await is free to return and do what it was doing which we know while in parallel the task inside the await will now run on another thread which we've just explained once the task is done it returns to either the original calling thread or carries on on the thread it was on to do the work derivatives the callin thread or carries on on that should really be another thread because it's not specifically always a thread so this is kind of explaining what I've just explained to just a sentence to explain what I've just been speaking about so that's kind of another section done of you well that's describing what a task is and seen the task in the async and the awaiting action so now because this is probably starting to get confusing we really need to give it kind of an analogy so we'll move on to the async analogy so let's just copy and paste a header and it will say async analogy and this is now a way to try and explain I guess what async is in terms of say a real-world example so considering our like coffee let's imagine you go to Starbucks and the entire shop is run by one person and is inventively named mr. UI thread so you walk in and you ask mr. Thor head for a vanilla latte any obliged using starts to make your coffee so it puts the milk in the container turns on the hot steam and basically proceeds to stand there while the steam warms up the milk and tries to get to 70 degrees so during this time you basically realize that you want something to eat you quite hungry so I'll have a muffin so you shout over to mr. thread and you say you know can I have a muffin please and he just ignores you because he's basically blocked he's waiting for there the milk to boil so he's thread is blocked I mean this is the analogy of the blocking thread it's it's one thread Doom one task and while that task is happening the milk spoiling the thread has to wait for the milk to boil before it can proceed to do anything else so several minutes go by three more customers come in and they're all starting to queue up and the waiting to be served and I'm finally when the milks finished and his ground the coffee and major latte it returns to you and naturally you'd be a little bit annoyed you've just been ignored for three to five minutes while he asked for a muffin he didn't turn around he didn't acknowledge you at all it was like he you know he didn't even know you were there which you wouldn't do because he was blocked waiting for there the milk to boil so you decide to leave them off in get your drink and go and sit down and then he considered continues to serve the next customer and one at a time doing the same job over and over and obviously that's not a good situation so this is what's happened in single threaded applications and this is what is you know does happen this is what the UI thread does there's only a single thread that conserved the UI and this is the reason why if you do any intensive work on the UI thread directly your entire UI your buttons don't respond your animations don't respond you can't move the window and that's the same analogy as you know the owner of Starbucks that's it's busy standing waiting for milk to be served just like your application might be waiting for a site to download a file so this is kind of the analogy of a single-threaded business a single threaded application so in order to improve the business mr. thread decides to employ two new members of staff called mrs. and mr. worker thread and the pair work independently and as mr. thread takes orders from the customers he asked Missy's worker thread to complete the order and then without waiting for Messi's worker thread to finish the drink proceeds to serve the next customer so once Missy's worker thread has finished a drink instead of having to take her drinks to the customers she asked mr. worker thread to serve the drinks and then without waiting she proceeds to start the next order so this is an example of you know a three thread eat system a three thread each application so basically what happens is you the owner mr. UI thread can happily take orders from customers and then once the commenter need to be made he asked mrs. worker thread so thread number two to go and make that drink and then mr. worker thread is thread number three and this job is that once the drinks are made it goes and takes them to the table and comes back so that all three work independently and all three have callbacks if you will or they can resume to each other and give each other tasks two of what to do so that nobody's hull held up waiting for somebody else and this is kind of a loose relationship between general multi-threaded applications and that's what we're trying to achieve is this kind of this work happening you know asynchronously so hopefully that little kind of analogy gives you some thought pattern into what happens when one thread is doing all the work versus when we're splitting off onto these second threads and those work sir you know happening independently so no that was any use but you know that's kind of an analogy I've come up with so I'll just put this analogy in here and basically the the key point here to note is when were explaining this and the key thing at the very top of a well the very top of this example is what asynchronous is and it's to start something and you don't well wait while it's happening and if we kind of read the example I've just explained then you've got like a key line here then without waiting for the worker thread to finish the drink proceed to serve the next customer so this and itself is Canada the nod towards why something's asynchronous because things are happening alongside each other in parallel so hopefully that's some analogy explained of what should be going on with async it's also got you a basic example of a task and how to use them which to be honest using tasks is not a complicated thing as we mentioned all you have to do is return a task and then in your task you're free to await and ultimately that just allows you to then do whatever you want a synchronously which ultimately boils down to being you know a task at the end of the day so now we'll really move on to the digging deep into what actually happens with the task so you understand you know the inner workings so we'll start with showing what happens in the synchronous part of a task so this is also an important thing to see so we have all up there right so this will be the synchronous in tasks or a synchronous part in tasks because some of you may know this I'm guessing you'll be watching this video that you don't but tasks and in terms of say well anyway you see an async or needs returning a task so this is now a task function if you will this code some of it actually runs just like a traditional synchronous call like this call and I hinted to eaten the last explanation that when you call into this that this part of the call up until the first wait is actually run in the same threat doesn't actually turn on that's the wrong comment there doesn't actually turn asynchronous until I hits as a wait so up until that point it's a synchronous call and ultimately when it's compiled it's still a synchronous call it never changes because this gets changed anyway but that's you know in terms of looking at it this is an asynchronous method but an important thing is to be aware of what's happening in what thread as I say that's the only real importance that you need to know about tasks as be aware of what threads run so you understand the importance of what threads you're going to lock off and what's gonna happen when you return so let's just do another example first let's just make a private static task and we'll call it do work and it won't do anything specific all's we'll do is say we will log doing work for and again the importance is thing for who of somewhere a synchronously for somebody who we are doing the work for and the only point in this is to show what threads happen when so we have well I guess this is also trading how to actually make an asynchronous method done work for so this is just gonna log that we're doing work for somebody and then we've done it we'll make it an asynchronous task so we can actually do it and it should as convention states we should name it async at the end of it so do work async is now the name of the function and then the work itself we want to do an asynchronous work but we also want to log what's happening as you mentioned that's what we can't do here so the simplest way to now make an asynchronous method if you will will just do dynamically and we'll await it though so we'll await and we'll just do a task run and at a stop run allows you to basically cut inside here a method or a delegate so just you know your normal lambda expression to make a method to run now we can type whatever kohu want in here and it's going to run on a separate thread to this that's all there is to making something asynchronous you know what it's the simplest way so now in here we can say doing work on in a thread for such-and-such and then in here we'll just simply a weight tossed up the lake and we'll just wait at the typical half a second so this will be the logger start a new task so it runs on new thread or rather different thread is there the key here and doesn't necessarily mean it's new because task uses a thread pool which might pick a existing thread and then as mentioned an odd to await something we can call a sink into the inner method that we're calling so this then turns into a method that wants a task and now the task is returned here so we have a delay and then finally an important thing to explain and then it will be once we're done working on the that because you'll also notice your surprise here so all this call is gonna do is it's gonna come into here it's going to log the thread it's gonna start up asynchronous work which means it will spin up on a different thread so we know this that will now be different from this thread well then do something which doesn't matter this is just fake work to do nothing and then we'll also log once we've done that work and then finally when we're here which should be after both of these calls because we've all waited it and then we'll return to the caller but what you'll notice is this will help us explain what happens and where and you could always step through the code but now we've got the logs you can we don't need to step through we can run it and then explain it so we will call do work async and again we need to wait at a strong just because we're not on we're all that we can't delay the task run come on I just do tasks run don't wait which should compile I think it's just complaining it's a complaint about doing a soon there we go so this will be for me in too many matter so run some work to show the threads or the second finished part of the call so let's just run this and then I'll explain what's happened where so we'll have the classic downloads had not bothered about for now so now we get into here so in fact we've forgot an important step that's to actually log anything out here kind of the whole point of what kind of show so we've done the work will log it like everything else and then what do we typically do we say before summer thread after summer said so before do work thread and then after do work that so let's see what happens here so if the Downloads happen right so here we come into this which we know now what happens we do at a stop wrong which bends up a new thread and then we synchronously wait it simply to bring it back into the console you know thread so that's that's not important for what we're doing this better than the important bit so we start work on the before thread which is thread eight and now we say do some work but what you'll notice is this is asynchronous we're saying to do this on another thread so everything inside of this function you'd think is now on a new thread which means do work for me should be on a new thread but you'll notice do work for me is on the same thread as the caller which actually means we're holding up the thread so even though it looks like we've said async and that there's now work you'd expect to start up on a new thread the important thing here is it doesn't actually do that it's it's locking the thread at the point of up until the point of the await and something else we can do to show that as well which we'll show separately in a minute is to do let's first get that task so we'll just save our do work task equals the Tuscan that we don't await it you'll notice we got a task back so as I mentioned what do you think would happen here if we do this you know let's run it and see so we haven't awaited the call so what's gonna happen so firstly you'll see before do work then you'll see doing work for me is on thread 5 still and then after work is on thread 5 and now inside here doing work on an death threats carried on and all of us we don't care about right now but the important thing here is you'll see that we've done before do work threat doing work for me and afterwards so even though we haven't awaited what's happened does it still run the code up to a certain point and that point is the first to wait and and it must do that in order to do what we said and that's to return a task of a promise for work to be done later so in order to return a task it must hit the point at which it's awaiting a task so what happens when you call this function and you don't await it is or even if you do awaited the same thing happens it just changes the flow upwards but the way we've just called the method as it comes into here just like a normal method it hits this hits the log and then at this point it returned so it returns here and there even though we haven't stated we turn this is effectively done you know return tasks run for in essence we've returned the task so we've actually run this line of code directly in the same thread as we were in so if we put a breakpoint on this you can see it happening and you can see the call stack doesn't change so we're on here we're on thread one I believe yeah and then in fact all we never been on thread one before on thread five why is my thread window not right anyway well oops let's run that again for a breakpoint before I can so we hit here now if some reason I needed to step over once to show so wrong thread eight or we know yes there we go so before they work federal thread eight now here we press f11 you'll see I'm still on the thread eight and I'm also importantly I'm still I can step back up the call stack I'm still here I'm still in this code so right now this is running like a normal function so I'm on the same thread I haven't changed threads I'm still on the same call stack nothing's changed I'm still exactly where I was I'm inside this function running in the same thread so this is nothing asynchronous right now but importantly at this point you step over and unfortunately the step over scanner showed that to happen we wanted to have a breakpoint ts let's just do that once more so we step in we go through we get to here and then as I press this you'll see it's come back here so we've actually returned a task and then we've got the the code here there's still you know running line by line so the point of what I'm trying to explain here is that let's comment this so we will say do work this will return a task and run the lines of code inside the method up until the point at which the first await is hit and this is important because say this was your UI thread and you're in WPF and we'll get there we'll make it'll be PFR and let's make the presumption that you were awaiting this so I've split it up just for simplicity and then you can do a weight do work cast you can you know do the await afterwards doesn't matter you're waiting a task but I wanted to show that at this point work still happens and the await happens here that's no different than doing a weight you know that but then you can't see the split of what's actually happening that the steps in between which is one it does return a task and you can get the task and then it awaits it it just in lines these two actions so by getting a task back and then awaiting it it's just a shorthand of or rather this is the shorthand to simply await it in the first place but by doing it this way you can see that this line runs just like a synchronous method so everything before the first await here it's run on the same thread synchronous was a UI thread and a button was clicked and then here you had some huge amount of work the dead thread thusly 10,000 say and we didn't await a function which we haven't so if we don't await the function and we get to here we'd expect to get to here next then what you'll find is that you'll hit here we should step over and it hangs for 10 seconds and then gets to the next step so you can see it's running on that thread so if that was your UI thread right now work that was done asynchronously if you were to do what is natural to appear like fully asynchronous which is this if you were to do that then you'd find that even though you'd expect this to run on a new thread so there you go and you should hit here right after it doesn't it's it's locking the thread so it's it's a very important piece of information to be aware of that when you see async it does not mean that the code inside is necessarily running on a different thread it only changes thread at the point of the first await and if this await gets hit at first it goes then into this function calls this await so it'll still run this up until the point of the first await basically is there you know the important piece of info and then the bit that awaits they say this will then spin off to a new thread come back but the result so at that point if we then run the function and look at the output we can see what happens in terms of the threads so we have the work thread which is eight then we know that when we go into there and created it was this bit for us on the same thread so it's doing work for eight it hits the await so it returns so we get up to here now and then we've awaited the task so at that point this says right hold up free up my thread but go and do you work on the other thread so then the inner work these two lines spin up a thread to do four and the important thing here as I mentioned this is this happens all the time so even though we're in an asynchronous call here and we've went out on around that Hamilton log when we await again every single await does the same thing so the await now is going to go into here and say well this wants to happen on its own thread so we're waiting a task that awaits a task has actually spun off another thread so we're now this line of codes on thread for this one's on thread 5 because the callback happens that way so if we were to repeat this you know multiple times and run this code then what you'll see is each time it's changing threat I mean it's reusing threads because of the we know the father the previous threads have been freed up but the important thing is every time you come in after and await the threads changing so that's something to bear in mind especially on UI threads that what happens with you know they're the threads when you're awaiting things so I'll just put all this into the notes to keep them up to date so the synchronous parts well to be honest there's no notes to be made I've kind of made them in the comments so this is the synchronous part so I'll just wrap this in a region they sync run us part of tasks and then end region there and then you might just want to get it you know a coffee or other breaks this is quite long video and refresh your mind and then you know come back to here as we move on to you know the other bits we still got quite a bit to go to to really explain tasks so the next thing I will do is explain return types so we'll do a sync return tarts this is fairly simple it's not as complicated as the best so for an asynchronous task as we've seen we can return void we can return tasks which are both a way table operation well rather the tasks await the bull avoid isn't bought it returns nothing so in terms of wanting to do some work that returns a value then if we copy and pasted the whole thing do work and get result and then if we want to get some info back then we would change the task to a generic type of task with the return value so let's say we want to return a string and now it's going to complain that we're not returning a string so you can return a void you commits in a task or you can reach in a task that actually does return a value which means that you simply await for a result so if there was a call that was going to return something then that's where the await returns a value and that's what happens in here so this download string is actually a task of string like we're doing now so I'll show you how to do that and that's no different than thinking of like this method a task with a string if it wasn't asynchronous you'd remove async you'd remove task and you'd remove the brackets and this is what you're looking at it's just a private static function that returns a string so bowles we've done is wrapped in a task and put a sink in but ultimately it's just you can ignore async task that just means it's asynchronous the ultimate thing is we're returning a string so in here because we've already awaited a task we've done something we can now return just a string and we'll just return the value we passed in to us return what we received so now if we were to call that method for do work result equals do work and get result we turn this that right now will obsolete a task which is not what we want we need the result so we could do dot result which is something you should almost never ever do so there's very rarely ever a case that you want to directly access the result of a task because this is a complete this basically boils down to the the way back often come in a blocking wait so you don't ever really want to do result what you can do is give a weight and then get the result from the task which is slightly better not massively but slightly better doesn't block the thread entirely but because we're on a synchronous thread here the the console app is running on this one thread and it's synchronous we have to keep jumping off to tasks and then weighting them so we could do that we could do tasks run and then do our work and then dot weight afterwards you know to await the work like we've done before but I'll show you a slightly different way save them and spin up a new task you can save our do work result task equals get the task as we've seen get the task wait for it so then we do VAR results do work results or rather it just P do it with all tasks dot wait get the result and it would be the work path but result at that point because we know it's complete that is the same as simply converting to as we've done in every other example at a stop run and then we're waiting on it there and then inside here now we're free to simply do before do work result equals do work and get result return this and that's typically how you'd see it written in a one-liner this is the other way of doing it so in hindsight I'll simply comment that out or rather I'd say do it well now I'll I'll comment it out because that's not I'm just showing you a different way of doing it you can get the task you can wait it and then you can get the result that's if you're in a situation where yeah you're in synchronous and then the other way is to simply spend up a task and wait the task and then get the result so you've you've done it a bit safe away so I'll comment that way out or fact I'll just delete that way to it now holy man I just don't like commenting out to be honest so let's just read unit and we'll say method one getting results park a sink from sink that's what we're doing and then copy that region it's a longer region name but who guess that's the other way do it result two as then get this so we run this and simply breakpoint here and run and see all the other code running then we'll get to here and ultimately we don't wait in the next line and then we now have the string so that's all we've done and then in terms of threads you can see what's happening with threads we also need to put some breaks here doing work we haven't put any breaks in but you can see the yeah it's not very clear let's clear that up so we have synchronous parts after work done we've waited let's just get a breaking line to chuck in there it's the line separation then method one would want line separation and method two and there we go in fact still want something different we need to change nobody have to return this return this to yeah that's fine so now I can see the last call we did which was this result here we do move return this for which will be the thread we've got here which we haven't logged in a threat as we've mentioned jumps on the separate ones and comes back onto a different thread returning but you've seen all out the previous examples the point here was to mainly show you the return types how to get a result from an asynchronous call so now we've made a call that returns a string that simply you know does whatever it needs to to await whatever it's doing in its own code let's say synchronous and then returns a value so that's really all this to the return types as there's void which can't be awaited there's a task which can simply be awaited put is like a void action it's like you know a void method it does nothing but it's an asynchronous for ewl and then there's finally the the task with a return type which is just like any other method that returns the type so I'll Chuck these notes in about the return type so you can only turn void tasks for a method marked async as a method is not complete when it returns so that no other result is valid which basically means as I mentioned the method does actually return at the first weight so the only thing it could possibly return is a task which is a promise of something to be completed in the future so there's nothing else it could return because it needs to have a promise of doing this work afterwards so that's why it's the only valid sort of answer so that's that one wrapped up we are to return type so the async keyword will mention next so as I mentioned earlier briefly and a hint of it was the async keyword we see here you know in all your functions it's not actually added to the method declaration signature and by that I mean if we were to say make an interface so we were to do public interface something and you were to define it it's basically like voyage test and it's a function you couldn't add a sink to it because a sink is not actually a signature and you'll see complaints the modify icing is not valid doesn't even tell you why but the reason why is the only effect a sink has on a signature on a method declaration here the only effect this has is to change the compiled code so it tells the compiler that inside your code wherever it sees in a weight is to completely change the structure of your code so it does something very similar to the the event callback style code so let's take the simple example of this one and let's pretend we were going to compile the code and tweak it so this saw the async here and they couldn't you know compiled the code what would happen is it would say oh there's there's an async here the first thing it does would be to remove the async that doesn't exist now at this point it then returns the task but before returning a task what it does is stores or parameters as n these here local variables so if we declared any variables here it would store those all the contexts so do with these the calling context the synchronization context execution contact security context everything to do with you know the thread and the affected with the context at which this code is running it and then it would also store this variables which means the class in which this code is running because you could have a local class variables like these private ones here so the point of hitting and await it first then and it physically writes as code so it's it compiles and outputs code so here it would then store all of those variables then it would start a new thread or rather it would ask the thread pool to start a new thread and then to run this bit of code so it would almost convert it to and again not in any way directly like this it would say well there's a new thread go ahead and do this the guys asked for a nice pretend nitrogen's in there I was weeping and then after it started in you've read it would then now return a task which is a new task of whatever it wants with a promise of the work to be done and again it's it boils down you can't write it because it's not the code that's available to simply raipur it does store all the variables starts a new thread off or starts to work off on the thread pool to go ahead and do that work and then it returns a task that it's expecting and that's in a task will now be hooked into this thread and at the bottom of the thread when it's finished it would then do a call bar and this callback is part of the thread which would then say right now I've got access to all these contexts and what I'm gonna do is make use of the context to try and find out where I should do my work this synchronization context otherwise I'm just gonna start up another thread and call back the code and this bit here after the await becomes the callback so as well as storing that it would then say do or call back equals and it would make a new callback method from that code and it would say whatever like say this is the compile code but then it would call the callback you know in similar terms as that so it's kind of what we did with our event based callback but all that's kind of you know it's fake code on trying to show you but what actually happens is this async does do a similar thing a lot more complicating a lot more structured but in essence it physically alters your your method call and in another video I'll actually install.net reflector and show you that physical change in code but for an intro to tasks I don't think we need to go you know that deep but it does important to know what the async word does it does actually change their physical compiled code and the key point is it actually does your your method really does return at this point the first await this code doesn't actually happen then all this afterwards is not part of this code anymore but the point of tasks is that it makes it look like it is it's nice easy way to visualize that waiting code than something else is happening without having to worry about making the threads and jumping back onto the right threads and things like that so that's what that is just paste my code as always and put the notes and hopefully that's all you know it makes sense that you're getting knowledge that you really do need to understand tasks so it's like say explaining tasks I could do in five minutes and that would be you know here the first way of doing a task and then the second way doing a task can return the result and I could say there you go that's how you use tasks but the most important thing in tasks is really to just to understand what's going on with the threads more so than you know anything else so one little topic that really are kind of covered anyway has you been doing this but I'll do specifically is consuming async methods and typically you can do this in most places the first way to finish humanizing method so let's say I would do work and buy consume I mean effectively you know call the work so what's the best way to consume this to to run this code and you call it and it's awfully going to complain it's going to be run synchronously so that's not really consuming it in the right way the best way to consume an async method is to become asynchronous yourself that's by far the best way so you typically go async tasks and then you can happily consume the method as run away table and now you've successfully consumed the method so that's the first thing the best way by far is if you can be asynchronous be asynchronous and that leads to a natural natural event with a sink again a sinkers clusters contagious for that reason that when you get an async function your natural thing as I have got of a waiter it's kind of almost forced upon you and you should you want to drive that asynchronous behavior and in fact when Silverlight was around and popular the only option you had in in Silverlight was to be asynchronous because the Microsoft team drove it that hard that the the forced asynchronous throughout the whole framework so you had no choice so the first thing is the best way to consume them is to be asynchronous yourself if you can't then please do not do this do not just get a task and do dot result this one's gonna be ten any work but say again you know Val you don't do dot result because what happens there is this is a complete and utter blocking call this will do nothing more in the most part as you're blocking wait call it will completely lock up your entire thing and destroy the whole point of the asynchronous behavior you can also cause deadlocks this way so don't do dot result there's a few options if it's got a result itself we can do dot wait but in terms of doing that what you have to first do is to store the task so that before do work result task which I think we've already mentioned above I just got less work result tasks some work or consume tasks might code consume so you saw the task wait for it which is a you know a better way of waiting doesn't deadlock your thread it's simply uses I believe probably ultimately in the the underlying code I think that's London using a threading time which doesn't then hold up any threads that completely the operational to do whatever they want it's not a blocking call so you won't get a deadlock and then finally now you can get the result so that would be work result equals work result task dot result which are now safe to get because the task is complete whereas if you try to access even read the result before it's ready it would block so you shouldn't do dot results until you know the task is finished and by waiting you know it's finished or at all throughout one or the other so that's that's way one so this will be consuming way consuming one I don't know what to call this way consuming wait I guess that's what I'll call it consuming wait obviously like say the first best way is to be a sickness yourself so another option is to be asynchronous so copy and paste that consuming by a task which is really doing no more than what we've done here really this is the the ultimate way of doing it this is really your answer if you if you're forced to be synchronous and the only option is to wait that well rather that is the only option to get from asynchronous or synchronous really your best using the wait and then getting the result of you need it the other option is exactly the same thing is to simply as we've seen many times here is to just start up a new task so car on a sink and I would personally use this method over the other and then wait it so that's what I would do myself as my personal preference start screen view consumed by task none of you want the result you'd obviously declare the result so far were resolved by a task then that would have to be your expected type or you could do bar equals default string or at NASA and then this would be work result by a task equals a weight and you can cross the boundary like that so even though this was created on one thread it's set on another do be aware there was we've mentioned and we've shown in this whole sort of video is you know this is not going to be on the same thread as this so this is a UI element you can go ahead and just say button dot text equals this here because you're not on the same but you should be aware of that now with what I've spoken about you you've got in your mind that you know this he's threatened umber certain one this is a second thread anything coming after this await here would be another thread compared to that thread and so on and so get resolved this is the other way I'd do it and then before I forget let's chuck the breakline in there and also the breakline there let's just run and make sure that's looks ok still keep them all separate yeah there we go so you can see as you mentioned the different threads been involved so that's how you would consume a task again let me just dump my comment into here the best way to consume or call a method is to return of a task is to be async yourself in the caller that's ultimately ultimately awaited rather and by that definition basing methods naturally contagious which is what I mentioned and then some examples here so that's consuming so we're not too far off the end now of the basics of tasks and feel they'll be more videos on the more complicated ones so now we're going to talk about more specifically I know of briefed over it but I want to really reiterate this point because if you understand what happens in a task you won't have any issue going forward in the future videos to further understand what's going on so what happens during an async call and you might say we've just spoken about that but I want to be very systematic in this definition so what we're gonna do is paste my very specific notes and we'll talk through them one at a time so you can really get into your head exactly what's happening in enough detail that what you care about and what you need to know is in front of you you can always read back and you know reference this document if you get confused so as we mentioned code inside a function that returns a task which is these for example so this code inside a function that returns a task that's what we're talking about and in fact can we split the screen there we go perfect right so code inside a function that returns a task this code runs its code on the callers thread off until the first line the call awaits so that means the thing that called this do work async our thread above the work up until the async there happens on that exact same thread as if it wasn't in the function it's not in any way asynchronous at this point in town once it's hit the first await that the current thread executing your code is released meaning it's released in the sense that this function gets returned so as we see this actually does return and that's why it's released it they can carry on because it's been returned it physically I was returned even though you don't see it in code because it happens at compile time so the current thread executing code is released making your code asynchronous at that point because it's no longer waiting on the the rest of the work to happen so this means from a normal point of view your function has returned as we mentioned and it's returned a task object and that's why it's free because now it's got the task it carries on and the task gets you know monitored and handled afterwards once the task you've awaited completes your method should appear to continue from where it left off as if it never returned from the method so resume is on the line below the await or rather there if you're assigning something like the result equals await then it returns to the result section but ultimately what that means as once you go here and you hit the await you'd expect this code to all happen and then naturally below this it happened after so what you're seen as a sequential almost synchronous appearance of code which is the point of tasks so you can look at this work log here now and and see that this unit of work that you're trying to do in your head happens in a linear order which is what you need in your head it's easy to understand it's how code works you can think of it as this happens and this happens and this happens and this happens and this happens that's exactly what does happen and in order to make that happen and to make it asynchronous as we know this unit of work must happen on a different thread in order for this to be asynchronous but we don't really have to care so much about the fact that this has gone off on a different thread and the thread this is called from is allowed to free up we're not overly concerned about that but it's important to note that the point of the task is to allow that natural flow to happen and appear that it happens line after line so to achieve this and see see show up at the point of reaching the awake call here so right before this then delves in as I mentioned it stores all the local variables so that means that we've got verbally and equals something here the ill store here stores the parameters of the call stores the class variables and it stores all the contexts which I don't need to delve into but things like security of you're impersonating a user on the machine you're on the execution contacts the corne contacts all the contexts of your your thread are stored and that's that's fairly not massively but that is consuming on the CPU and there the memory to do that and then on resuming once it's stored all those and starts all this on resuming so here afterwards it basically restores all of those values as if nothing had happened and that's the point of it it makes it seamless so if you were to pop vol or rather say var I equals 68 here and then afterwards down here checked if I equals 68 it will because even though at that point in time it gets stashed away on the garbage heap and then this runs when it comes back and before this line executes it restores those values for you so that you have no real you no recollection of anything changing so that's what's happening on you know during a call so now we want to delve a bit deeper and go into what happens with threads during the call which again we briefed over but will go very specific here and so you can understand what threads get called and when and also start involving the UI thread so let's just place that and the and then I'll shock my notes into here now so let's talk about the thread specific information about task now so when I were repeating ourselves a few times here relax it's important so we'll start off the reading from here now so there's your call a method that returns a task as we've seen and it uses async inside the method all the code up to the first two wait runs like a normal function on the thread that it called that call it and that's what we just mentioned in you know the statement above but this is now focusing only on threads so once it hits the await we've seen above what happens all the magic that goes involved the function ultimately returns a task to the caller and it does its work on the inside of the await so that means it does the work here the specific work on the inside of the await on a new thread or an existing one as we've seen we got a new thread because you go to the thread pool which spins up one or uses an existing idle thread once it's done so once that works finished and effectively after the await so whatever line needs to have an X which is here in this case after the await execution returns to a certain thread so we know it's changing thread or potentially not changing thread but it's it's returning the work on a thread that threads determined first by checking of the thread as a synchronization context which we can also get if we do in fact I can put a a little thing in here between the comments bar sink context equals synchronization context or current and we will see if we break points after the fact whether we've got a synchronization context in this console application so we'll see in here we have none so a console application doesn't have a synchronization context so basically the thread is determined by first checking we have a synchronization context which we don't if it does though which you will do in a WPF application and most UI applications then it asks the synchronization context for doing some work and that would be sync context coast and now it would post the method of you will that is compiled which would be this unit of work so I'll go ahead and at this point here at the start it would create a unit of work that comes after which is this and then at the end of it it will get the sync context and do post and tell it to do that work for us so that's what's happening there for UI threads and that have a sync context which we'll see doing a post on the synchronization context will Chuck the work to be run on the UI thread so what that means is in a UI application this unit of work here after any wait if the work was started on the UI thread any work after the UI thread will end up back on the same thread because of the synchronization context so if we're on the UI thread here and then we await something the beauty of it is that afterwards were back on the same UI thread which is a real real benefit to asynchronous work on UI stuff for normal threads like this case that I've no synchronization context the code after the awaits typically one always continues on the same thread that the inner worker has been done on so we just run the code you'll see that happening multiple times so we'll see where we've got synchronous work so where we've got asynchronous work you'll see here work on some inner thread thread for work done after there's a thread for on the inner eight after eight on the consumed wait for after four you can see that it's it's always typically continuing execution so this runs on say to a date then typically if there's no sink context this will also run on the same thread as this kind of bubbles in but it's not isn't always the case it's just a typical and you know very common case so that's the normal case if you use continue with instead of a wait then the code inside continue where the rooms on a different thread than the unit asked was run on and again that's the typical case so if we were to do say do work async test dot continue with will do test or say continue with and then in here we have the task that returns and we can log that so we'll do log continue with complete and we were to do the same thing with an a wait while we've done the await multiple time so we don't need to show that but we'll show a typical continue with VSA show can continue with typically changing read IDs and to show that we'll also log a breakpoint as we've done all the time the only difference here now is that continue with hopefully is our last statement because it's not going to wait or come we wait there yeah we can still wait there so if you just do that I don't think I'll change the behavior though so we should get down to continue with and we should see what we're talking about the difference so you can see there now previously the inner thread which was waited for awaited is on eight and then continues work on eight when we don't continue with instead then even though the works finished do work for continued with four that continued with complete is now on different threat altogether eight so they're just behaviors to be aware of they're a very common and almost always the case and I'll mention them here but it's not a requirement what is it a definite though is that if we are using UI and we we start some async work on the UI thread then the synchronization context is captured because we mention it here it's captured and when it comes to resume it asks a synchronization context to you know post the information back to the UI thread which also means that anywhere in code in a UI application we no longer need the dispatch we were talking about in the WPF applications good you can use synchronization got current the if you're on the UI thread they'll to post you know back to the UI thread so that means you can also store the synchronization context instead of the dispatcher if you want it to be a bit more cross-platform because this is in system threading it's not in any way specific to UI but that's another topic altogether so for normal threads that how we've read all right now where are we so this also means after every await the next line is typically on a new thread of there is no synchronization context which is what we've also shown when we did multiple awaits if we just pasted multiple awaits here you saw that the thread changes every time because it's the same every time you go from one await into another the same actions happening so every time you go into a wait this gets returned this gets queued this gets run and then you hit this away to then this gets run this gets queued and you know in the same principle so each time the logic of what thread we pick happens every single time and await hits and that's why every single time there's to read typically changes which is not a concern to us the only real concern you ever have with threads as one I just want you to understand the flow of it for a good reason to make sure you're not locking threads and to make sure things are happening where you expect but most importantly is you typically working with UI and in that case the thread is very important and you have to be aware of which thread run and then then finally there's an exception that if you use configure await false then the synchronization context is totally ignored and it's resumed and treated like there was no contact so we can't show this until we start up with WPF application which we'll do in a minute and then resuming on the original thread via the sync context is an expensive thing as we mentioned so in order to make sure we get back on the same thread all of the contacts in everything has to be stored and then all the variables have to be resumed and you know basically it takes time it's an expensive process so the only real time you'd want to use configure wait false is when say you're in a UI button click or something and you've clicked a button you've downloaded something and you're awaiting it and then the bit after here when you finish downloading you're not necessarily doing anything with the UI so you're not setting UI or maybe your short term view models in that case you might want to do a configure await false I just doing doc configure await false to say now you don't care about this this bit of code running on the same thread that the synchronization context wants you to so it's more free efficiency what you'll find most people end up using this for is to try and fix deadlocks in UI which is a bad reason if you're doing that you're doing something wrong so configure away is not a solution to get around deadlocks what it does is tell you that where you started the code if you're in a synchronization context environment which is typically UI that the bit after the await you don't care if it runs on the UI thread owner so it saves the expense of having to restore all that information so that's kind of the you know the bit there so I'll show basically the synchronization context and thread resuming section here about there you know the synchronization account demo this point of the thread resuming on a very specific UI thread which is different than what we see now in a minute we'll just cover one more thing which is exceptions so just remember that as we've seen here we've got no sync context right now so based on the example I've written and if we go here for normal threads that have no context the code after the awake typically but always continues on the same thread is the inner worker meaning the one that started it but it's no requirement to resume on a certain thread so it means we started work on that one and then we've resumed it on you know when it was finished on the bed five we started on five of June today it started on one with you and um for what you'll see in the UI thread is the work that starts on fed one which will be the UI thread always review on thread one so it's a different behavior and it's it's done for that reason the synchronization context to make sure that a waiting is a natural behavior that if you're expected to be on the UI thread here and you will wait some work to be done you naturally expect you to still be on the UI thread here yes that's the point of that so I'm not going to go into any major detail about exceptions right now we can always do another video on that but what I do want to do is at least cover exceptions so you can understand what's going on with them basically what happens and what to think about it so we'll say exceptions in async cause and again I'll just dump my notes in here so we have some basic rules here so any exception thrown that are not caught by the method itself so right now all of our methods are thrown into the task object so this is specifically when you're in a a method that returns a task so if we were to create a private static async task throw something throws an exception inside a task and we can do before the await and so throw before a wait because as as we mentioned there's two key differences here and then we just do away task delay to be honest we don't care about any specific delay and do throw a new argument exception oops so we've thrown and then we've awaited and that's just gonna tell us it's unreachable code which is fine just showing you as a a point of what happened if potentially it wouldn't throw in fact we just do you just do a single call with a boolean before and then if you just say if before and then if not we throw there so we always throw if it's got passed there either way and then that would have parameter throws the exception before and a weight so we have a basic function here simply throws an error nothing else let's start with the basic example of just calling that so throw before a weight and that's Control Alt + E and turn on exceptions and obviously say before is true so they're short in fact we should also log a console so log after throw before which sounds confusing now it's gonna be before throw before so maybe we do something like that so it looks a bit less confusing so now we should never hit that after throw before because it should crash the thread so what we should find is we get to there do all the work this throws and we take a quick look at here we've got before throw before but then because we've crashed and if we look at the thread Ron run thread one on the main thread because that's where we've called from it crashes or rather it should all crash the whole application interesting that hasn't crashed the application it's like just because throwing an exception is not or am I talking about my own point here that's throwing on the main thread but allowing it to continue let's just check this out so we throw the and then it crashes yes so it acts different even though and this you can the point of what I'm trying to explain here even though it's running on the same thread and this should in theory in all rights crash the application just like throwing here should because that's what you're thinking yeah if you throw here the application crashes but if you throw inside here even though that should perfectly crash the application as we mentioned async physically chained using this code so it's not exactly the same so what's happening is he knows it's returning a task and if you throw before then instead of it just crashing the application because you're expected to get a task back then it's gonna put that crash log if you will into the task so we do crash task equals task and then if we log here and we like crash what should happen is the exception gets put into the exception property of the task and it goes to as faulted so this crashes you're on the main thread in theory expected to properly crash yet it doesn't he carries on on the threat that apparently crashed that's because the async word has compiled it so that it doesn't it's got a try-catch around it now and instead the crash task now ask the exception count of one and it should have as faulted in Misco status have faulted which I'm sure there's a property called yes faulted which will check in a minute but can see important we've got the exception here and we got the inner exception so we know that the problem we've effectively caught it so one little quirk is that you'd think a throw before the await would crash and instead it doesn't so what we can do as far as faulted because I'm sure crushed ice castles faulted yeah did it crash which it did and this is just you know important to know and what to expect expected behavior the exception would be do the log crashed task got exception I think it sure compared to string nicely and we'll get a big dump out of the crash which we can do I don't think we really need to do that to be honest I can just do the message doctor string so we just get oops written but you'll see there's the crash if you will so it's not really important but you can see the exception is there so the exception message is easier to see that's this expected behavior that's different than what you would potentially think so if you don't wait the task the exceptional not throw on your calling thread which is what we're doing here we're not we're not awaiting it so it won't throw on the calling thread so really that should be kind of there that bit of showing there throw on calling thread without waiting and then if you do a way the exception will be we thrown on the calling thread so I'll crush as normal even though it's called before the await and that's we can't really show that here to be honest to ask to do that in there the UI application because the problem with this as we can't wait on this calling thread because it's obviously not gotten a wait but we can do we're in you know a single thread so we can't really a waiting cause it to crash that way but that's just a statement that you know if you could do a wait here then this would effectively crashed this thread if it crashed before and a wait so though is thrown here what I just the same as if you'd thrown outside of the await that's what you know it's it's about that's what it's saying so the exception to that rule is of the method with async as we'd and that's because the magic happens by detecting that it's a task and it's got somewhere to put the exception so it can say hang on this is crashed but I want it to return a task so I'm gonna chop this exception in the task if you've got void there's nowhere for that exception to go so it will crash just the same so then we can kind of show the same behavior as what have been in the other one so throws an exception inside avoid async so this can just be exception Boyd throw to be honest we don't do before or after or do we well we don't really show it after it's kind of the point of it being after is that it would throw well let's leave that English for an option I wouldn't take note so throw before a wait for before a wait Boyd well before in fact yeah but before a white boy this really clear our third an exception inside of all unison before awaiting so in fact it's not before because we've got a boolean giving us the option so that's four wait and we say before so now in here the difference the only difference is we've changed the task to avoid and we'll do exactly the same thing so now what will happen is this will cross the application and we won't go any further so we will copy that and where's the exception so it's right at the bottom which is kind of fit for purpose because that crashes the application crashed tasks move and there's no point in doing that to be honest they've crashed asteroid because we'll never get anywhere and I can guarantee you that so throw a weight void and well before throw void I thought that's now before throw our weight which makes more sense so we'll void right so now you'll get to the before throw voyage it'll crash in it will actually now crash just as if it was on the same thread which crashed the application so you see that's the first throw that works its way this is another second throw it'll do the call stack we're at the second row so if we now Luke we've got to you've done them before and after we've done the before avoid but now importantly they should crush the whole application which now the applications in a break mode and it's crashed there's nowhere else you can go so that's what's happened there is there the exception is if you use a sink but there's no return type it changes the way which exceptions happen and also again it's more importantly any exceptions that occur in an async void re throat like this so if there's an a synchronization context exception is posted back so what that will do is in a a UI application of the exceptions thrown and the original caller was a UI thread it will be thrown back on to the UI thread specifically and overnight it's thrown onto the thread pool which is thread it's running on anyway so kind of the same issue but that's exceptions for you that's kind of a a point there so the end of your thing left is to show you the slight differences when it comes to WPF applications so I'm just going to spin up a new WPF application and we'll go from there so it's just a blank WPF application let's just change the main window type of stuff panel on button in content click me and we'll just do a click event for the sake of what we're doing so you can see we've got click me go behind and we now have some button to do something so we'd have to run this now the only thing we really need to prove and show here is there the difference in a waiting inside of a function on the UI thread and that you know the differences of what that means so we've got the button here there's no popper effect but you can see here's hover so this is a UI responding and then we click on run this function so let's first show some kind of locking synchronous call so let's just do thread lock sleep I'll show you this is what happens when you do synchronous work on a single threaded application so you got this you can see the hover effects I can drag the window click the button now the window won't move no hover effects and then five seconds later don't fit moves to where it was dropped and I've got hover effects back so click again drugged down here it's not happening no hover effects five seconds later it's gonna appear down there sexy basically it's like the Starbucks owner where wouldn't you give me to task in this case go sleep for five seconds nothing else in the world happens until that point this is what makes the UI unresponsive when you're doing work so this could be downloading somewhere from the internet or processing some calculation and this is why people end up getting slow UI when these same wise me UI not responding and it's because you're running it on the same thread this is the UI thread so let's start by copying over the I guess the helper method to first just to log something out to the console in this case we'll change it to debug so we can see or to be honest let's just make it run that'll do to debug is easy enough so we'll write the message to debug so now we've got the same thing so now we can say log do some work and then log finished doing some work so this is doing synchronous work on UI thread the ice that can be at region and and region and we can put a little private boolean and do sync when ice work equals true for now we're to do finish work on your thread or not and wrap that up why not and receipt or not I'll clean off and then Bolton Claire Kalpa functions right so we now have do synchronous work do some synchronous work we should be able to click the button and see an output down there and then we click the button and see do work on thread one and then when it's finished then it's finished work and this responds you can also see that this window moved before that kind of vlog outputted because it had all our cued up messages while this was asleep and then this got posted to be done after so that's normal synchronous work so I'm going to change that now to false and we'll do some asynchronous work which is you know the main thing we want to show so well first do the same kind of action so to do synchronous work we turn this event handler into an async void which as we know from the description in the last project that this means any exceptions thrown here now will bubble back up to the synchronization context post which will also end up you know crash in the UI thread so to first show that you know crush their dose rules to throw new exception or rather throw new argument exception oops spelled differently again and if we run this on the UI it'll just instantly when we click can I get this to stay where it is and if I click this button it will crash and then the whole application dies so we know crashing on the UI thread crashes the application so now we've got an async void we can now do let's just say await task delay which is the synchronous counter part if you will to thread sleep in a sense it's basically used to do nothing if you will but as we know it means do nothing on a different thread so what we can do here is [Applause] in fact I should start synchronous work and synchronous work and then start asynchronous work and asynchronous work so first thing is let's check out what thread this now runs on so start saying let's work on one and we resume now you can see on two and that's important because of we copy over the do work method which we can see the difference in the behavior if we were to paste this in and instead of delay you just do do work and do async work well now see more output in the log at which we need to know we don't was calling my guts fine so in here we clear this off click the button you'll see start in asynchronous work doing work for a sink one as we mentioned because when you first enter before the await it's run on the same threads this is UI thread and it does work for the inner thread so this bit on thread for so it's no longer on the UI then it waits and then it does the work afterwards on another thread but then importantly the difference is do work for async or don't work racing here the bit after the await is called the synchronization context and resumed on burn one now if you compare that output with doing an exact same work on the console then what you'll find is if we swap back over to the wvf outputted this output oh yeah and we want to show that there we go so we have the same in effect on any of these so you got do work for whatever which is one it's on the first two that do work for inner thread which is here on four and I don't like I'm fine with exactly the same threads just to kind of show not necessarily now so it doesn't matter you've got difference that here like four is eight he got five as four is five and five is eight there so you got you two pieces of any work happening on two different threads but then this regimes on eight where is this because it's got a sink context rooms on one so that's the important thing there is this now is running on the UI thread because it's been posted back and that's a key difference between if you've got a synchronization context or not in the application it does make a difference to where your threads you know what happens with the threads and what to expect so if we were to do the and the region we were to do a wait and then something through here or we wanted to edit they're doing a sync work on UI thread if we wanted to edit the button here so we'd have to jump into here give the bottom the name my button importantly my button got tapped equals or and my bot content rather new content you can see this should fail after so this you fail they should work after a second so we're in here would click the button and after a secondly change to new content because we're allowed to do that because you're on the same thread so let's start showing the important differences if we were to spin all this off and even if we were to Waititi doesn't matter if we do awaked a stop run so we know this all now run entire new thread we also know that UI based on the last video can't be changed outside of a new thread anything other than the the UI thread itself so now if we were on this what we'll see is we click this button you'll see the work started on thread for because we're in a new task so the work carries on on thread for then the inner work happens and it resumed on thread for nothing very special that just happened to be the case they didn't naturally resume on a you know the same thread for any special reason it just happened to be but the important thing is that the call to my book content can't work because we're not on the UI thread anymore so we know that obviously from the last video and we know that that's the case so that's just kind of showing it running purposely on a different thread but the way that a wait works is that because it uses the synchronization context that's what's allowing it to work so if we were to do this and I'm tried this far because you might do it good to set the synchronization context of this calling thread to remove it if you will so it's no longer going to make use of the the UI special synchronization context this should also no fail I think I have never tried this I'm literally editing the UI so there we go so because we've now destroyed the the UI synchronization context before we await it's now going to store this new synchronization context which doesn't care about the UI thread and then the await after now tries to resume on a different thread and then we get the same error so you can see the reason it's working is to kill you I sync context on capture in await if you would change the same context then it no longer be zooms on the UI thread run some async work log it and sure to resume on same UI thread thanks to Grand Isle a Shem context that's basically what it's doing and alls it's really doing is doing the synchronization context co-host and like say post in the the work to be done I don't know they can just do it that way you know like invoking manually for now many things at once which one's one such fine sake a post work here and then do my button contents equals something else and that would you know do the same thing of you well you posting back that's all the same context does he posted back to the UI thread so we should visual on the same UI thread set UI stuff along it so that's the important difference that if you at the point at which you do your pan of awaiting if at the point at which it captures the synchronization context it exists which it doesn't in UI so again if you were to do for you I think context equals signals on-screen text op current and we will just simply breakpoints and run here and have a look compared to the console application that had not the UI context has a dispatcher synchronization context which basically finds the dispatcher of the UI and does a post to the dispatcher which you spoke about in the last video so that's what I was doing and as I mentioned you could just to prove a point you could capture the synchronization context like a wait typically Ward you can kill it so it doesn't do it by default and then we could fix it by doing UI sync context post and then calling this inside of there and passing or as the object and I've never tried this but I'm pretty sure that should not work because we're still done what the callback would have done obviously not as efficient as letting the await actually handle it but you can see it's now worked it's got to here even though it's resumed work on thread 5 so we're now no longer on the UI thread here I've simply posted it back to the UI thread to do the work for us so that's worked I'm not sure what happened to be clogged again it's yeah it appears remembered so at the point of setting the synchronization context it's not it's not you know altered it for the whole lights it's somehow restored it's inverting after this point well that's just kind of proving the point that the synchronization context is the thing doing the and so that would kill it if we did that so remember UI context which would be that that would kill eats that work should resume and if not that's how we'd post so I'll leave those commented in just for your playing around pleasure if you will and that's the key difference so the one thing I did mention that will do the same thing almost as killing this is is if you didn't want if you weren't gonna set any specific content off here so you know you didn't care about you weren't in a UI stuff so this wasn't happening and you were just logging there's no point in getting back to the UI thread here at a cost so what you can do is you can just reconfigure a wait pulse to not bother coming back on the the same thread so then I would click the button you'll see again we start at one but we end up coming back at five so that's where you know we don't care about the UI thread what you will notice though is just because this configure wait force is here it doesn't stop the inner call which hasn't a wait here from returning the returning after this await on the UI thread so if you're going to use configure await you also really need to pass that down consecutively that everything every call that is inside the call you configuring a way to false would also then use configure await to false so you'd have to do it inside here as well which kind of then defeats partly if it's a point but it's very intensive and very you know you'd only really use this in optimized when you're really trying to highly optimized something and you're working on the UI thread but to be honest instead of doing configure a way to that stage I'd simply just spin it on a new task and just say you know tasks run get off the synchronization context in the first place and then you don't have to do this inside every single call so I'm hoping this explanation has been useful I know it's been a very long video kind of a neat dive but it's really important that you understand those concepts and most people don't understand this much about tasks they really don't fully understand it it's very evident that a lot of people don't get what's going on so even though this is a lot to take in I'd highly recommend just watching this video multiple times playing around with tasks and really if you understand this fundamental stuff all the videos I'll do in the future unlike simple methods or making use of tasks I won't have to deep dive I won't have to explain the point of things I can simply show you how I'm using them and they'll make sense I'll do a brief explanation saying you know we're jumping off this thread because of this reason and we're doing this and we're resuming but you'll fully understand an async an await a task continuing with compared to awaiting not awaiting you know when exceptions get thrown and why it's all very you know crucial information because like I say using the task is very simple you just simply and that's the whole point of tasks they're meant to look the same so if you go and compare a synchronous call to an asynchronous call really all so as to explain us that you do that then you return a task it's kind of there's nothing to explain but the the underlying thing that happens is the important thing understanding why this frees up the calling thread and why this would make you UI responsive compared to this one lock in your UI thread sort of thing so it's more about the principle but hopefully for a lot of time and effort into constructing this video and to constructing this explanation and being you know the best explanation I can be for a complicated topic if you want to support run do another our patreon page patreon.com/lenguin any support for what I'm doing is greatly appreciated as usual any comments or questions leave them in the video and I'll get back to everyone and you know hopefully this video was useful for you guys [Music]
Info
Channel: AngelSix
Views: 90,578
Rating: 4.448276 out of 5
Keywords: c#, task, async, await, ui, sta, threads, tasks, multi-threading, deadlock, deadlocking, cross-threading, parallel, tutorial, guide
Id: CzgDxdwTJds
Channel Id: undefined
Length: 154min 7sec (9247 seconds)
Published: Fri Apr 13 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.