Start here. This is the direct spoken answer to practice first.
Overview
Places semaphore and admission boundaries around scarce work without retaining unlimited tasks.
An asyncio semaphore can cap how many tasks enter a dependency call at once. I acquire it immediately around the scarce operation and release it with async with. But a semaphore alone does not bound memory if I first create a task for every input; those tasks still retain arguments and wait. I combine the permit with bounded task creation, batching, or a bounded worker queue.