Saturday, March 04, 2017

6 Simple Rules for Async/Await

  1. If a method A calls another method B that returns a Task (or Task<T>) then the calling method does not block on the completion of that task, unless it either:
    1. awaits that task, or
    2. waits on the result of that task
  2. The calling method cannot await a task unless it is declared with the async modifier, which causes the compiler to build a state machine (similar to the IEnumerable iterator) for that awaitable method.
  3. In point 1 above, the behaviour is independent of whether or not B is marked with the async keyword
  4. It is this non-blocking behaviour of A that allows the calling thread to proceed past the point where B is invoked. It's even possible for the thread's call stack to unwind, and for the thread to go back to reading the Windows message queue if it was the UI thread.
  5. The compiler will only warn you "because this call is not awaited ..." if B was marked with async.
  6. It is expected that A will do something with the Task returned by B; at the very least there should be some code to check that the Task did not throw any exceptions. If - instead of B - we have an async method C that returns void then we do not present A with any opportunity to monitor the completion of C. Unobserved exceptions thrown during the execution of C could indicate corrupted program state and can be configured to terminate the application in much the same way that an unhandled exception in synchronous code can unwind a stack fully and terminate the process.

No comments: