async and await let a method stop waiting, give its thread back, and pick up where it left off when the work finishes. The method does not get its own thread, and marking something async does not make it faster.

Asynchronous programming is about not blocking a thread while you wait for something outside your process, usually a disk, a network or a database. Multithreading is about doing more than one piece of work at once on more than one core. They solve different problems and the articles below keep them apart.

A Task is a promise that a result will exist later. A Thread is an operating system resource. You almost always want the first one, and the framework decides whether a thread is even needed.

Once two things run at once you need to protect the data they share, so the later sections cover locking, the concurrent collections and how to cancel work that is already running.

Async and Await Fundamentals

What async actually does, and the comparisons that clear up most of the confusion.

Running and Combining Tasks

Starting work, waiting for several pieces of it, and the loop mistake that quietly makes everything serial.

Async Streams and Cancellation

Producing results one at a time without blocking, and stopping work that is already in flight.

Locking and Synchronization

Protecting shared state once more than one thread can reach it.

Concurrent Collections and Threads

The collections built for concurrent access, and working with threads directly when you really do need to.

Where to Go Next

Async code touches these topics constantly:

Never block on async code with .Result or .Wait(). Make the calling method async and await it. That one habit prevents most async deadlocks.