Challenge 1: Timed Sequential vs Threaded Downloads — Possible Solution ==================================================================== import threading import time def download(name): print(f"{name}: starting") time.sleep(2) print(f"{name}: done") # sequential start = time.time() for i in range(3): download(f"file{i}") sequential_time = time.time() - start print(f"Sequential: {sequential_time:.2f}s") # threaded start = time.time() threads = [threading.Thread(target=download, args=(f"file{i}",)) for i in range(3)] for t in threads: t.start() for t in threads: t.join() threaded_time = time.time() - start print(f"Threaded: {threaded_time:.2f}s") Output (timing will vary slightly, but always roughly this shape): Sequential: 6.01s Threaded: 2.01s WHY THIS WORKS AS AN ANSWER ------------------------------ The sequential version reuses download(name) exactly as defined in the chapter, called three separate times in an ordinary for loop (Course 1, Chapter 4) with no threading involved at all — each call must fully finish (including its 2-second time.sleep(2)) before the next one starts, so three calls take roughly 3 x 2 = 6 seconds total. The threaded version reuses this chapter's own threading.Thread setup exactly: three Thread objects are created (not yet running), started with t.start() in a loop, then t.join() is called in a SEPARATE loop afterward — starting all three threads first, before joining any of them, is what lets all three sleep(2) calls overlap in time rather than running one after another. time.time() before and after each block reuses the timing pattern from Course 2, Chapter 6's @timer decorator challenge, applied here as a plain before/after measurement instead of a decorator, to make the speed difference directly visible rather than just asserted. The chapter's own explanation is why this works: time.sleep() releases the GIL while waiting, so even though only one thread can run Python bytecode at any single instant, all three threads can be simultaneously "waiting" during their sleep(2) calls — bringing total time down to roughly 2 seconds (the length of ONE download) instead of 6 (the sum of all three).