What is async/await?

Simply put, async and await are syntactic sugar for the handling callbacks. The basic idea is that when you call a method with await, it tells the compiler to wrap that bad boy in a Task and to pass it to the Task Scheduler. The Task Scheduler then executes the Task, and then the code following the await that is dependant on the Task is run. The two following examples are functionally equivalent, but the Async/Await way is more readable.

Callback flow

class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Run Callack");
        GetPosts( results => Console.WriteLine($"GET /Posts (Callback):{results}") );
    }

    static void GetPosts( Action<string> callback )
    {
        using (var client = new WebClient())
        {
            client.DownloadStringCompleted += (sender, e) =>
            {
                Console.WriteLine( "Runing WebClient Callback");
                string pageSourceCode = e.Result;
                callback(pageSourceCode);
            };

            client.DownloadStringAsync(new Uri("https://jsonplaceholder.typicode.com/posts/"));
        }  
    }
}

Async/Await flow

class Program
{
    public static async Task Main(string[] args)
    {
        Console.WriteLine("Run Async");
        Console.WriteLine($"GET /Posts (async): {await GetPostsAsync()}");
    }

    static Task<string> GetPostsAsync()
    {
        using (var client = new HttpClient())
        {
            return new HttpClient().GetStringAsync("https://jsonplaceholder.typicode.com/posts/");
        }
    }
}

*See The Awesomeness that is async Main()

WTF are Tasks

Task are basically what they sound like they are, little bits of work, that can be done asynchronously. They generally come in two varity: Task and Task<T> where T is the “return” value of the Task. In case it isn’t obvious, you would use the generic Task<T> when you need to retrieve a value, otherwise just return the plain ol Task.

Got’yas

There are a couple things you need to keep in mind when working with async/await:

  • Tasks are not threads.
  • Tasks that are awaited run in a sequential queue unless told to do otherwise, ie Paralell.ForEach(). Think nested callbacks for each await (not exactly but close enought for this article).
  • Tasks may be run on a different thread then called, but the results are then marshalled to the calling thread.
  • Tasks are cheap but not free. Every time you wrap/unwrap a Task with await you are paying a cost.

Da Rulze

  • If you don’t need the awaited value in a method, don’t use the async keyword and just return the unadulterated Task.
  • Methods should return either Task or Task<T> except for when called by an event delegate, ie. Button.clicked then they may return void1.
  • Method names should end with the word ‘Async’.
  • “Async all the way”, Don’t be switching between synchronous and asynchronous. Pick one, and be confident with your decision.

Until next time, keep Hackin’.