Start here. This is the direct spoken answer to practice first.
Overview
Chooses a concurrency model from workload, libraries, isolation, runtime build, and operational cost.
I use asyncio when the call chain is awaitable and spends most time waiting for I/O. Threads fit blocking I/O libraries or code that releases the GIL and can safely share process memory. Processes fit sustained CPU-bound Python work or stronger isolation because separate interpreters can use multiple cores. Each model adds different scheduling, state-sharing, cancellation, startup, and failure behavior.