Definition
A thread is a separate line of execution inside one program, and threads share memory. The Global Interpreter Lock (GIL) lets only one thread run Python bytecode at a time in standard CPython. So threads help when waiting on input and output, but not for pure calculation.
In simple words
One cook in a kitchen can start the rice, and chop vegetables while it cooks. That's threads with waiting tasks. But the same cook can't chop two onions at the same time, and that's the GIL with heavy calculation.
Why it matters
Knowing this tells you which tool to use. Downloading 100 files? Threads. Crunching numbers? Use multiprocessing or NumPy, which releases the GIL for many operations.
How it works
In code
import threading
import time
from concurrent.futures import ThreadPoolExecutor
def fake_download(name):
time.sleep(0.2) # waiting, like a network call
return name
start = time.perf_counter()
with ThreadPoolExecutor(max_workers=5) as pool:
results = list(pool.map(fake_download, ["a", "b", "c", "d", "e"]))
elapsed = time.perf_counter() - start
print(results)
print("Took about 0.2s, not 1s:", elapsed < 0.6)
counter = 0
lock = threading.Lock()
def add():
global counter
for _ in range(10000):
with lock:
counter += 1
threads = [threading.Thread(target=add) for _ in range(4)]
for t in threads: t.start()
for t in threads: t.join()
print("Counter:", counter)Output
['a', 'b', 'c', 'd', 'e'] Took about 0.2s, not 1s: True Counter: 40000
Common mistakes
- Using threads to speed up heavy Python calculations.
- Sharing data with no lock, which leads to bugs that appear only sometimes.
Check yourself
Summary
- The GIL allows one thread to run Python at a time.
- Use threads for waiting tasks.
- Protect shared data with a Lock.
Finished reading?
Sources: Python docs: threading