Brandon Minnick - Async/Await Best Practices

Sign in to queue

The Discussion

  • User profile image
    wkempf

    Good discussion.

    I'd like to point out there's another reason to always "observe" a task's result, one that maybe will resonate with people better. Every time I've mentioned that you should always observe a task, someone always wants to avoid it (probably because you have to write more code) for "fire and forget" methods. After all, you're not "forgetting" if you have to keep ahold of this Task in order to observe the result. When you point out the exception topic they'll respond with, "but my Task won't throw an exception" (presumably they have a blanket try/catch). My response is "not good enough." Why?

    When the main thread of your application ends, the process goes away unceremoniously. Any work your background task may have been running will just end midstream. Imagine you've got a background task running that's writing data to a file asynchronously and the user exits the application, causing your task to be interrupted and only part of the file gets written. Disaster! While you can still contrive scenarios where even that doesn't matter, I'd say it's too risky that code changes will put you back into this disaster mode. Always observe your tasks!

  • User profile image
    kellyelton

    Task.Wait() does throw unhandled exceptions, but they're wrapped in an AggregateException and the stack trace is a bit different.

  • User profile image
    Ondrej​Valenta

    Hi, just an observation from a central european guy who has seen quite many training videos all over the internet like Pluralsight, Udemy or even thi channel. If there was a button to speed up the video I would be tapping it franatically. Americans have a tendency to "sing" their words too much and fill the sentences with words like "so" , "cool", " awesome" and this video is great example of that. You, Mr. On left (sorry can't remember your name), could you please cool down a little bit and keep it plain and simple without all that hype and motivational/advertisment stuffing. It's great there is a service called Azure Mobile Services and I understand you have to promote it but all you had to say was "I used async/await when I was for example connecting to AMS, so guys go check it out, I think it's a service you will find very interesting and the pricing is very reasonable as well". 

    When you said "so far we are doing an awesome job" after changing just one line of code I had to pause the video to vent out all the hype. (I just now remembered Louis CK video on usage of words like awesome and amazing.) It's like watching LA teenage girls talking.

    I realize my comment seems and actually is too direct and harsh and honest (central european problem + sagittarius + rooster) but imaging you have to watch dozens of videos like this one and instead of keeping plain, simple, direct presenters starts to express their feelings and talk slow.

    This could be ten fifteen minutes video. Think about your viewers, they have families and other stuff to do as well.

    Ondrej

     

     

  • User profile image
    VirtualVoid

    lost me at `async void`

  • User profile image
    jjones

    Great discussion - coming from a pure "Threads" background, I hadn't found a good introduction that explored the variations and common examples of Task<*>.

  • User profile image
    tgrt

    lost me at `async void`

    I assume you're referring to the constructor for the command. The Execute() method for an ICommand doesn't return a value. It's considered to be, like event handlers, an acceptable place to use async void.

  • User profile image
    RiperZec

    I am not sure about some of the info in this. First you should never run async stuff in the constructor of a class, no matter if you use a command. You always use UI events like OnInit equivalent also never do try catch in the constructor. And in regards to the catch block you can use the .Catch on the method for you to send a message to the UI even when you don't use await. So this is just a problem of unhandled exceptions not something specific to async await at all.
    Wait is fine to use and sometimes good if you have done task like in many cases With FromResult Wait wont have any negative effects and fill perform better. The real problem with Wait are deadlocks since not all tasks run in different threads. And if you must use Wait you probably should rewrite the code to be sync.
    ConfigureAwait can be tricky and you should not just use it all the time, you should be careful with it as well.
    The using problem is much more difficult than in the video most of the time you want the object being disposed asap and unnecessary waiting for the task to be done can create problems. And why would you make a async function with side effects on the stream?

  • User profile image
    wkempf

    @RiperZec:

    Lots to disagree with here.

    Constructors should just initialize an object, yes, but that doesn't mean they shouldn't ever create a task. It's unusual, but not wrong.

    As I pointed out, there's more to observing tasks then just ensuring you handle exceptions, and there's plenty wrong with using Wait(), Results and kin in async code. Google "async all the way down" for deep discussions on the topic.

    ConfigureAwait isn't tricky, and it should always be used when you have no need to sync back with a SynchronizationContext (such as needing to get back to a UI thread). In fact, failure to do so can actually result in deadlocks.

    I'm not 100% sure what you're referring to in your last paragraph, but it sounds like you're advocating not using await within a using? Can't agree there. I'm also uncertain what you mean by "why would you make a async function with side effects on the stream", but that sounds like you're being too philosophical. Yeah, side effect free code is always better, but the reasons you'd make synchronous code with side effects is the same reason you'd make asynchronous code with side effects. Heck, I/O is the very definition of a side effect, and the best place to use async is with I/O.

  • User profile image
    Oleksiy

    I would recommend to read about eliding async/await over here.

  • User profile image
    JoseMarino​Albernas

    Really enjoyed this conversation.  I did learned a couple of very important facts:

    a). I do not need to async/await "all the way" and instead return the Task of whatever and let the caller decide how to handle that.  Love it!

    b). ConfigureAwait(false)  I lost in an interview because I did not know how to ConfigureAwait and what it does.  Well now I know and it was explained in simple words.  Love this too!

    Really enjoyed it!  Thanks!!!

  • User profile image
    pavone

     Good talk, thanks for the video. I actually had to learn the ConfigureAwait during a Production issue and introduce it as a hotfix, it brought some memories watching you discuss it. 

  • User profile image
    princedc

    If I do not use ConfigureAwait(false), does that mean thread 0 which executed the till await keyword waits for thread 1 (which executed the async code) to complete and will not be used for other computation.

    If thread 0 is used for other computation and thread 1 finished in the mean time. Will the computation wait for thread 0 to become free. Will the code execution be blocked will thread 0 is available.

     

  • User profile image
    Mordo

    Great video. Thanks for showing what is really happening in IL. I would like to notice one important thing. After refactoring of GetStory, in the catch block we should not return null anymore. It should be Task.Completed. Otherwise you will have to check if this task is not null in the executing method.

  • User profile image
    bcronce

    @princedc: If you don't use ConfigureAwait(false), when the task completes, the point where it was going to pick back up from would have to be on the same context. A context can only be executed by a single thread at a time and could have a backlog of tasks to execute. It's a point of contention.

     

    If you don't care which context you execute from, then use ConfigureAwait(false).

  • User profile image
    Zack

    EWWWW Region blocks...

  • User profile image
    Daniella

    Great points, thanks for the learn.

Add Your 2 Cents