Gen AI Developer Classroom notes – 21/Oct/2025

Threads vs Async vs Parallel

  • Synchronous: Tasks will run one after another, each blocks until finished
  • Threading (multithreading): Multiple folwos of execution inside one process share the same memory
  • Async: A single thread co-operatively runs may coroutines switching at await points
  • Parallelism: Multiple process on multiple CPU Cores, Each has its own memory interface
from concurrent.futures import ProcessPoolExecutor
import math, time

def cpu_bound(n):
    print(f"start {n}")
    s = sum(math.sqrt(i) for i in range(100000000))
    print(f"s = {s}")
    print(f"End {n}")
    return n

if __name__ == "__main__":
    start = time.time()
    with ProcessPoolExecutor() as ex:
        results = list(ex.map(cpu_bound, range(4)))
    print("Took ", round(time.time() -start, 2), " Seconds")
  • When to use What
Workload Type Sync Threads Async Processes
I/O Heavy (HTTP, DB, Disk) No yes Better yes
CPU-heavy (math, ML) No No No Better
Realtime (Chat, Websocket) No NO Async NO
Simple Scripting Better No No No

Async IO in python

  • Where we will use AsyncIO

    • ORMs
    • Fast API
    • AI Agents
  • Why async exists

    • many programs wait (network, disk, sleep), while waiting cpu remains idle
    • Async lets one thread cooperatively juggle many waiting jobs, when one awaits I/O, another runs
    • It gives concurrency for I/O bound work
  • Three words:

    • Awaitable: Anything you can await (a corouting or a Task)
    • Coroutine: A function defined with async def that can be awaited.
    • Task: A scheduled coroutine managed by the event loop
  • Event Loop:

    • A loop that drives all asynch work: it schedules, paused at await, resumes when ready
    • Entrypoint: asyncio.run(main()) creates a loop, runs the main and closes the loop
import asyncio

async def main():
    print("hello")
    await asyncio.sleep(2)
    print("world")


asyncio.run(main())
  • Coroutine: Creating and awaiting
import asyncio

async def fetch_one(n):
    print(f"start {n}")
    await asyncio.sleep(1)
    print(f"done {n}")
    return n * n


async def main():
    a = await fetch_one(1)
    b = await fetch_one(2)
    print(a, b)

asyncio.run(main())
  • Task: Scheduling multiple coroutines concurrently
import asyncio
import time

async def fetch_one(n):
    print(f"start {n}")
    await asyncio.sleep(n)
    print(f"done {n}")
    return n * n


async def main():
    t1 = asyncio.create_task(fetch_one(5))
    t2 = asyncio.create_task(fetch_one(3))
    r1 = await t1
    r2 = await t2
    print(r1, r2)

start = time.time()
asyncio.run(main())
print("Took ", round(time.time() -start, 2), " Seconds")
  • Gather many tasks
import asyncio
import time

async def fetch_one(n):
    print(f"start {n}")
    await asyncio.sleep(n)
    print(f"done {n}")
    return n * n


async def main():
    # t1 = asyncio.create_task(fetch_one(5))
    # t2 = asyncio.create_task(fetch_one(3))
    # r1 = await t1
    # r2 = await t2
    # print(r1, r2)
    results = await asyncio.gather(*(fetch_one(i) for i in range(1,6)))
    print(results)

start = time.time()
asyncio.run(main())
print("Took ", round(time.time() -start, 2), " Seconds")

By continuous learner

enthusiastic technology learner

Leave a Reply

Discover more from Direct AI Powered By Quality Thought

Subscribe now to keep reading and get access to the full archive.

Continue reading