Task, async, and await

Benefits of Asynchrony

  1. Unblocking the UI thread This only maters to WPF and WinForm applications but does not mean much for Asp.NET applications. Asp.NET applications are automatically multi-threaded. For details, please see How Asp.Net process requests with Threadpool

    Asp.NET vs WPF Threading Model

  2. Increase parallelism (process a single request faster) Throw more CPU at the computation so that it can finish sooner.

  3. Increase Throughput(process more request) Thread is a OS resource, it consumes space in the OS tables and ~1MB of memory. Blocking a thread is waiting all the resources that a thread allocates.
    This normally, won’t matter much for WinForm and WPF applications. But it does for Asp.Net applications. The default maximum number of thread pool threads for.NET 4.5 is 5,000. In case of thread starvation a.k.a all threads are busy, Asp.NET will first try to create more thread. And when the maximum limit is reached, it will start to queue HTTP requests. When the is full, it will return HTTP 503 (Server Too Busy).

    some math about synchronous http requests

    • 1 sec duration, 5000 requests/sec without queuing
    • 100 ms duration, 50000 requests/sec without queuing
    • 10 s duration, 500 requests/sec without queuing

But this math is only true if we have unlimited amount of CPU. If 10% of the request process duration is CPU time, and we have 16 cores on a machine. Then above math will change to

  • 1 sec duration, 100 ms CPU time, 160 requests/second without queuing
  • 100 ms duration, 10 ms CPU time, 1600 request/second without queuing
  • 10 s duration, 1 s CUP time, 16 requests/sec without queuing

Asynchrony in Detail

await

Split the code into different states in a state machine The details of the threading model of the state machine are shown below

Console apps are special

stack spilling

If await split code into multiple pieces and run in different threads, how can local variables be shared between different stages. .Net enables stack variable sharing by hoisting them into heap and restored them back onto stack

thread ambient information

If a single method is split into pieces and run in different thread, then do these different pieces of code see different thread ambient information (e.g. SecurityContext, CurrentCulture, Principle). Historically these information by design, before TPL, async/awiat are invented, are attached to the running thread.

Thread ambient information is captured into an ExecutionContext in the thread creating the calling the await, and restored to the thread executing the continuation.

exception handling

MVC Exception Filter Http Exception Filter Application_error Will not catch exceptions throw from the background thread await will transfer exception to the awaiting thread

Unit Testing

unit testing threading model is different than Asp.Net, WPF, and WinForm not clear how it compares to Console apps. It depends on how NUnitTestRunner runs the testing. On main thread? or on thread pool thread.

Difference between Await, ContinueWith, Awaiter

evaluation order

Code Snippets for Reference

SynchronizationContext

    public virtual void Post(SendOrPostCallback d, Object state)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(d), state);
    }

AspNetSynchronizationContext

    public override void Post(SendOrPostCallback callback, Object state)
    {
        _state.Helper.QueueAsynchronous(() => callback(state));
    }

DispatcherSynchronizationContext

    public override void Post(SendOrPostCallback d, Object state)
    {
        _dispatcher.BeginInvoke(_priority, d, state);
    }

SynchronizationContextAwaitTaskContinuation

    private static void PostAction(object state)
    {
        var c = (SynchronizationContextAwaitTaskContinuation)state;
        c.m_syncContext.Post(s_postCallback, c.m_action);
    }

References

Written on March 4, 2017