C# 5.0 – Async/Await – Async/Await



C# 5.0 – Async/Await – Async/Await

0 0


m-lyons.github.io


On Github m-lyons / m-lyons.github.io

C# 5.0

Async/Await

Created by Michael Lyons

Part 1: Beginner

Benefits of asynchronous programming

  • The UI thread is responsive.
  • There are a reduced number of threads.
  • You have access to web/file resources without blocking.
Oh hey, these are some notes. They'll be hidden in your presentation, but you can see them if you open the speaker notes window (hit 's' on your keyboard).

Async/Await

  • Keywords in C# 5.0.
  • They help make asynchronous programming easier in C#.
Async and await are keywords introduced in C# 5.0 to improve asynchronous programming in C#. They look and feel like magic but they aren't. The goal of this presentation is to have you understand what they are and how to use them. It's okay if you don't fully understand how they work.

Example

              
    // Asynchronous Method
    public async Task<int> DoSomethingAsync() {
        await Task.Delay(2000);
        return 0;
    }
              
            

Naming Conventions

  • Async methods are typically suffixed by the word Async. e.g. DoSomethingAsync().
  • Sometimes an api will have two methods: an async method and a synchronous method.

Async

  • The async keyword tells the compiler that the method is asynchronous and may not finish completely before returning.
  • The async keyword wasn't actually needed to implement this but the compiler team thought it was best to be explicit.

Usage

    public interface IAsyncService
    {
        Task DoSomethingAsync(); // note there is no async
    }

    public class AsyncService : IAsyncService
    {
        public async Task DoSomethingAsync() // awaitable
        {
            await Task.Delay(100);
        }

        public async void DoSomethingElse() // void
        {
            await Task.Delay(100);
        }

        public async int GetIntAsync() // Compile time error
        {
            await Task.Delay(100);
            return 0;
        }
    }
            

Await

  • The await keyword can be used in front of an awaitable type.
  • The most common awaitable types in the .NET Framework are: Task, Task<T>, and YieldAwaitable
  • There is no IAwaitable interface but if there was it would look something like

Under The Hood

    public interface IAwaitable<T>
    {
        IAwaiter<T> GetAwaiter();
    }

    public interface IAwaiter<T> : INotifyCompletion
    {
        bool IsCompleted { get; }
        void OnCompleted(Action continuation);
        T GetResult();
    }
            

Demo

Part 2: Experienced

Exceptions

  • Exceptions with async code are propagated up to when the user accesses the result of the awaitable.
    public async Task<int> ThrowAsync() {
        await ThrowsExceptionAsync(); // thrown from here
        var result = ShouldThrowAsync().Result; // will also throw here
        var task = ShouldThrowAsync(); // will throw here when
                                       // exception happens before await
        // ...
        result = task.Result; // will throw here when it happens after
        return 0;
    }
            
  • You cannot use the await keyword inside of catch block or finally block.
  • These features are implemented in C# 6.0 which will be arriving in early 2015.

Async Lambas

  • There is support for async lambdas and delegates.
  • These are regular lambdas or delegates that are prefaced with the async keyword and return void or an awaitable type.
    Action action = async () => await Command.ExecuteAsync(new object());
          

Threading

  • So far you have seen asynchrony happen on one thread.
  • This approach works for lightweight time-consuming network operations.
  • But we need to use multiple threads if we are doing a lot of work.
  • Task.Run() is used to start a task in a new thread.
  • It is by far the easiest way to manage multiple threads
    public async Task<int> DoSomethingAsync() {
        var tasks = Enumerable.Range(1,1000000)
                      .GroupBy(i => i % 4)
                      .Select(g => Task.Run(() => SomeCalc(g.ToList())))
                      .ToList();
        var sum = 0;
        foreach (var task in tasks.InCompletionOrder())
        {
            var result = await task;
            sum += result;
        }
        return sum;
    }
            

Demo

Part 3: Testing

Problems With Testing

  • Delays work, but in big projects they become impractical.
  • Testing frameworks can't test async void methods.

The Time Machine (Tardis)

  • Created by John Skeet this class allows for manually controlling the flow of time around async operations.
  • You can schedule task completion and advance units in time.

Demo