🔍

Exploring Async/Await Mechanics in C#

Aug 28, 2024

Understanding Async/Await in C#

Introduction

  • Understanding how things work can enhance usability and performance.
  • Misconceptions exist about the implementation of async/await in C#.
  • Aim: Build a simple version of async/await from scratch without focusing on performance.
  • This session is aimed at a 300-level audience (intermediate to advanced).

Asynchrony vs. Concurrency

  • Asynchrony enables operations to be launched without waiting for them to finish, allowing other tasks to be initiated.
  • Concurrency refers to multiple tasks executing potentially at the same time, needing synchronization.
  • A thread pool is central to concurrency, which queues work items for execution.

Implementing a Simple Thread Pool

  • Thread Pool Basics: It queues tasks which can be run asynchronously.
  • Creating a Simplified Thread Pool:
    • Use a BlockingCollection to manage queued tasks.
    • Use threads to process tasks, blocking on the collection when tasks are unavailable.
    • Distinguish between foreground and background threads.

Handling Execution Context

  • Execution context flows ambient state across asynchronous calls.
  • AsyncLocal: Used to store state across asynchronous operations.
  • Implementation: Capture the execution context when queuing a work item and restore it when executing.

Building a Task Framework

  • Task Object: Tracks completion state and can manage continuations and exceptions.
  • Task Methods:
    • IsCompleted: Checks if the task has finished.
    • SetResult and SetException: Mark task completion or failure.
    • ContinueWith: Adds a continuation that runs when the task completes.
  • Synchronization: Use locks to manage state changes safely.

Implementing Task.Run and Await

  • Task.Run: Queues a delegate to run asynchronously, capturing exceptions.
  • Implement Delays: Use Timer instead of Thread.Sleep to avoid blocking threads.
  • Continuations with Await: Implement continuations using task state management.

Advanced Task Management

  • Task.WhenAll: Manage multiple tasks, waiting until all have completed.
  • Iterate: Implement a function to manage task sequences akin to async/await.
  • Awaiter Pattern: Allows tasks to be awaited by the C# await keyword.

Conclusion

  • Building from scratch provides deep insights into the async/await mechanism.
  • Such knowledge helps in better understanding and utilizing these constructs.
  • Encouragement to delve deeper into layers of abstraction for a solid mental model.