Limited Concurrency with a Semaphore
Hard · Async
asyncio.gather(*coros) runs coroutines concurrently and returns their results in the order you passed them, no matter which one finishes first. To avoid overloading a server you often cap how many run at once with asyncio.Semaphore(limit): async with semaphore: waits while limit coroutines are already inside.
The starter has a fake async job(name, units) that sleeps units * 0.01 seconds and returns "<name> done". Write async def run_jobs(specs, limit), where specs is a list of [name, units]. Run all jobs concurrently, but with at most limit running at the same time, and return their results in input order.
The driver check_run_jobs(specs, limit) is already written. It returns your results and max_running, the highest number of jobs that were running at once. It should equal min(limit, len(specs)): the jobs start together, but never more than limit of them.
Next: Async Retry with Timeout