~/problems
Problems
Basics first, then the classics, then company-style assessments. Every problem has tests you run right here; multi-level ones unlock as you go. See the roadmap.
Thread pool / concurrent crawler
ThreadPoolExecutor, asyncio, thread-safe visited set.
Notes
Recognise it when: lots of independent, I/O-bound work: crawling, fetching, calling APIs, processing files.
with ThreadPoolExecutor(max_workers=8) as pool:
pending = {pool.submit(fetch, start)}
while pending:
done, pending = wait(pending, return_when=FIRST_COMPLETED)
for f in done:
for nxt in f.result():
if nxt not in seen:
seen.add(nxt)
pending.add(pool.submit(fetch, nxt))
- A coordinator thread owns
seen, so there's no lock. If workers update shared sets themselves, guard them with a Lock. - Use
ProcessPoolExecutorfor CPU-bound work (the GIL). Functions must be picklable, meaning top-level. - For asyncio,
asyncio.Semaphore(k)bounds concurrency andasyncio.gatherfans out.
5 problems
Concurrency
Pools & pipelines Thread pools, crawlers, producer/consumer buffers.
Thread pool / concurrent crawler
- Basics: parallel map with a pool basics easy
- Fastest weather station wins easy
- Image transformation pipeline with processes 3 levels Anthropic medium
- Concurrent web crawler 3 levels Anthropic medium
- Multithreaded array sort 2 levels medium