Skip to content

← Concurrency with Threads and asyncio step 2 of 56

Easy Primitives

Download Pages with a Thread Pool

Your program needs to download a list of pages. Each download spends most of its time waiting for the server, so doing them one after another wastes time. Use a thread pool to run several downloads at once.

There is no real network here. FakeWeb.fetch(url) stands in for a download. It waits a moment, like a slow server, then returns the page. It also records the largest number of fetches that ran at the same time.

download_all(FakeWeb(), ["a", "b", "c"], max_workers=3)
# ["<html>a</html>", "<html>b</html>", "<html>c</html>"]

What to write

Fill in download_all(web, urls, max_workers):

  • Call web.fetch(url) once for each URL.
  • Use concurrent.futures.ThreadPoolExecutor to run up to max_workers fetches at the same time.
  • Return the pages in the same order as urls, even when a later URL finishes first. URLs that contain "slow" take longer, so the tests can check the order.
  • Wait for every fetch to finish before you return.

max_workers is at least 1, and urls can be empty.

What the driver checks

Keep FakeWeb and solve as they are. solve returns:

  • pages: the list download_all returned.
  • overlapped: True if at least two fetches ran at the same time. A plain for loop gives False.
  • within_limit: True if no more than max_workers fetches ever ran at the same time.

With a single URL, or with max_workers set to 1, nothing can overlap, so the expected overlapped is False.