Limiting concurrency in Python
A semaphore caps how many coroutines are in the expensive part at once.
import asyncio
async def fetch(name, semaphore, live):
async with semaphore:
live.append(name)
peak = len(live)
await asyncio.sleep(0.01)
live.remove(name)
return name, peak
async def main():
semaphore = asyncio.Semaphore(2)
live = []
tasks = [fetch(f"job{i}", semaphore, live) for i in range(6)]
highest = 0
for coro in asyncio.as_completed(tasks):
name, peak = await coro
highest = max(highest, peak)
print("never more than", highest, "at once")
asyncio.run(main())
How it works
async with semaphoreacquires and releases around the work.- The limit is what keeps a crawler polite.
as_completedyields results in finishing order.
Keywords and builtins used here
asyncawaitdeffetchforlenmainmaxprintrangereturnwith
The run, in numbers
- Lines
- 25
- Characters to type
- 474
- Tokens
- 136
- Three-star pace
- 110 tpm
At the three-star pace of 110 tokens a minute, this run takes about 74 seconds.
Step 3 of 4 in Async in depth, step 50 of 53 in Pythonic Python.