{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "kernelspec": {
   "display_name": "C#",
   "language": "csharp",
   "name": ".net-csharp"
  },
  "language_info": {
   "name": "csharp"
  }
 },
 "cells": [
  {
   "cell_type": "markdown",
   "id": "asy00",
   "metadata": {},
   "source": "# Async and Await\n\nModern C# programs constantly do things that take time: read files, call APIs, query databases. `async`/`await` lets your program stay responsive during waits instead of blocking the thread.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "asy01",
   "metadata": {},
   "source": "## The Problem: Blocking\n\nA synchronous file read blocks until the OS returns data. Nothing else can run on that thread meanwhile.\n\n```csharp\n// Blocking \u2014 thread is frozen during the read\nstring text = File.ReadAllText(\"data.txt\");\nConsole.WriteLine(text);\n```\n\nIn a UI app or server this is a problem \u2014 the app freezes, or throughput collapses under load. The fix is *asynchronous* I/O.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "asy02",
   "metadata": {},
   "source": "## `Task` \u2014 a Promise of a Future Value\n\n`Task` represents an operation that will complete in the future:\n\n- `Task` \u2014 completes, no return value (like `void`)\n- `Task<T>` \u2014 completes with a value of type `T`\n\nYou don't manually create `Task` objects \u2014 you `await` methods that return them.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "asy03",
   "metadata": {},
   "source": "## `async` and `await`",
   "outputs": []
  },
  {
   "cell_type": "code",
   "id": "asy04",
   "metadata": {},
   "source": "using System.Net.Http;\n\n// async marks the method as asynchronous\nstatic async Task<string> FetchAsync(string url)\n{\n    using var client = new HttpClient();\n    // await suspends THIS method until the HTTP call finishes\n    // \u2014 the thread is free to do other work meanwhile\n    string content = await client.GetStringAsync(url);\n    return content[..200];  // first 200 chars\n}\n\nstring result = await FetchAsync(\"https://example.com\");\nConsole.WriteLine(result);",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "asy05",
   "metadata": {},
   "source": "## Async File I/O\n\nAll major I/O APIs have async counterparts. Prefer them in any method that already has `async`:",
   "outputs": []
  },
  {
   "cell_type": "code",
   "id": "asy06",
   "metadata": {},
   "source": "// Write a file asynchronously\nawait File.WriteAllTextAsync(\"out.txt\", \"hello async\");\n\n// Read it back\nstring text = await File.ReadAllTextAsync(\"out.txt\");\nConsole.WriteLine(text);  // hello async",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "asy07",
   "metadata": {},
   "source": "## Rules of `async`/`await`\n\n1. A method that uses `await` **must** be marked `async`.\n2. An `async` method returns `Task`, `Task<T>`, or `void` (avoid `async void` except for event handlers).\n3. `await` can only appear inside an `async` method.\n4. `async` does **not** mean the method runs on a background thread \u2014 it means it can *yield* its thread while waiting for I/O.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "asy08",
   "metadata": {},
   "source": "## Running Multiple Tasks in Parallel\n\nUse `Task.WhenAll` to start several async operations and wait for all of them:",
   "outputs": []
  },
  {
   "cell_type": "code",
   "id": "asy09",
   "metadata": {},
   "source": "static async Task<int> SlowAdd(int a, int b)\n{\n    await Task.Delay(100);  // simulate slow work\n    return a + b;\n}\n\n// Start both without awaiting immediately\nvar t1 = SlowAdd(1, 2);\nvar t2 = SlowAdd(3, 4);\n\n// Await both together \u2014 total ~100 ms, not 200 ms\nint[] results = await Task.WhenAll(t1, t2);\nConsole.WriteLine(string.Join(\", \", results));  // 3, 7",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "asy10",
   "metadata": {},
   "source": "## When to Use Async\n\n| Good fit | Not needed |\n|---|---|\n| Network calls (HTTP, gRPC) | Pure CPU computation |\n| File or database I/O | In-memory data manipulation |\n| Any operation that waits on an external resource | Short, synchronous helpers |\n\n> **Rule of thumb:** if the underlying API has an `Async` variant, use it \u2014 and make your own method `async Task<T>` in turn.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "asy11",
   "metadata": {},
   "source": "## Practice\n\n1. Write `async Task<string> ReadFirstLineAsync(string path)` that reads only the first line of a file asynchronously.\n2. Use `Task.WhenAll` to fetch three URLs simultaneously and print the length of each response.\n3. Write `async Task<int> CountWordsAsync(string path)` that reads a text file and returns the word count.",
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "id": "asy12",
   "metadata": {},
   "source": "```{rubric} Footnotes\n```",
   "outputs": []
  }
 ]
}