threading runs tasks concurrently. The GIL limits CPU parallelism but threads help for I/O tasks like network requests. Use Lock to protect shared data. ThreadPoolExecutor is the cleanest high-level threading API.
Threading
import threading
def worker(n):
print(f"Thread {n} running")
threads = [threading.Thread(target=worker, args=(i,)) for i in range(5)]
for t in threads: t.start()
for t in threads: t.join()
# Thread-safe counter
lock = threading.Lock()
count = 0
def increment():
global count
with lock:
count += 1