Skip to content

C# .Net Asynchronous Coding

Provides ability to work with multiple threads

process ⇒ application
thread ⇒ smallest unit that can shared cpu time

Asynchronous Coding is NOT parallel programming

Many threads and few cores ⇒ lots of threads waiting

When you create a thread you are never sure when the thread will start or get processor time.

Getting threads from the OS is expensive.

Solution: app gets a 'thread pool' - threads in this pool are reused to save repeatedly getting threads from OS.

async and await - enable you to write asynchronous code, but do NOT create thread(s)

A useful property to check when working with threads is Environment.Current.ManagedThreadId

Creating Threads

Creating a new thread from the Thread Pool

var customers = await Task.Run(
    async () => 
    {
        await 
        // do stuff
        return customers;
    }
);

Waiting for multiple threads to finish...

var task1 = Task.Run(async () => .... );
var task2 = Task.Run(async () => .... );

var result = Task.WhenAll(task1, task2);

Task.Run takes from the thread pool -> not ideal as can run out of threads in the thread pool.

Can create threads manually:-

var thread = new Thread(async () => { actions });

// or for tasks that will task more than 0.4 seconds..
Task.Factory.StartNew( () => { your code here }, Task.CreateOptions.LongRunning )

async AND await

Normally this is all done within the libraries you consume (e.g. ASP.Net), but you still need async and await to allow the framework to use the threads. e.g. in EFCore the Async methods are handling their own threads.

Cannot await void, can only await Task<..>

Manually "awaiting"

var thread = new Thread( () => { <code here>; result = ... }) {
    IsBackground = true
};
thread.Start()
while (thread.IsActive) {};
return ask.FromResult(result);

This method is more powerful but also more complicated.

In ASP.Net await Task.Run doesn't make sense. You're already in a thread and are stealing another thread from the thread pool.

Never create a thread and immediately await it in ASP.NET core.

await Task.Run makes sense when in the main thread.

Using Task.Run

var result = Task.Run( () => { code here} );

// do other stuff

var x = await result();

Running several actions indepent of each other

var num1 = Task.Run( () => { ... code here... });
var num2 = Task.Run( () => { ... code here... });

var result = await Task.WhenAll(num1, num2);
return result.Sum();