Limit concurrent jobs
You have many asynchronous jobs but must run at most limit at the same time. A job here is a zero-argument async function, so nothing starts until you call it.
asyncio runs tasks on one thread. Tasks switch only at await.
import asyncio
async def main():
results = await asyncio.gather(
job_a(), job_b())
return resultsgather runs coroutines concurrently and returns results in the order passed in, not finishing order. If one raises, that exception reaches the awaiting code.
Semaphore
asyncio.Semaphore(n) is a counter of slots. async with waits for a free slot, and releases it on exit, even after an error:
sem = asyncio.Semaphore(2)
async def guarded(job):
async with sem:
return await job()Call the job inside the async with, so its work only begins when it holds a slot.
Your task
Write async def gather_limited(jobs, limit) running zero-argument async functions with at most limit running at once, and returning their results in input order. An exception from a job propagates unchanged. Raise ValueError if limit is below 1.
The explanation opens here once every check passes.