async_crawler.py in Python
Fetch many URLs concurrently and report sizes and timing.
"""Fetch several URLs concurrently and report sizes and timing."""
import asyncio
import time
import urllib.request
URLS = [
"https://example.com",
"https://example.org",
"https://example.net",
]
def fetch(url):
with urllib.request.urlopen(url, timeout=10) as res:
return len(res.read())
async def fetch_all(urls):
# blocking urllib calls hop onto threads; asyncio herds them
tasks = [asyncio.to_thread(fetch, url) for url in urls]
sizes = await asyncio.gather(*tasks, return_exceptions=True)
return dict(zip(urls, sizes))
def main():
start = time.perf_counter()
results = asyncio.run(fetch_all(URLS))
elapsed = time.perf_counter() - start
for url, size in results.items():
if isinstance(size, Exception):
print(f"{url}: failed ({size})")
else:
print(f"{url}: {size:,} bytes")
print(f"fetched {len(results)} urls in {elapsed:.2f}s")
if __name__ == "__main__":
main()
How it works
asyncio.to_threadruns blocking urllib on threads.gatherawaits them all with error capture.- Timing shows the concurrency win.
Keywords and builtins used here
asasyncawaitdefdictelsefetchfetch_allforifisinstancelenmainprintreturnwithzip
The run, in numbers
- Lines
- 38
- Characters to type
- 875
- Tokens
- 217
- Three-star pace
- 110 tpm
At the three-star pace of 110 tokens a minute, this run takes about 118 seconds.
Step 1 of 2 in Encore, step 52 of 53 in Pythonic Python.