Threads are useful for waiting work
Threads allow multiple tasks to make progress in one process. In CPython, the Global Interpreter Lock limits parallel execution of ordinary CPU-bound Python bytecode, but threads can still be effective when tasks spend much of their time waiting for I/O.
Shared state creates risk
Two threads accessing shared mutable data can produce race conditions. Prefer independent inputs and outputs; when shared state is unavoidable, use appropriate synchronization primitives and keep critical sections small.
Thread pools simplify common workloads
A thread pool manages a limited number of workers and is useful for many independent I/O operations. Do not create unlimited threads just because an operation is slow.
Practice: simulate several slow I/O tasks and compare sequential execution with a small thread pool.