A thread is a second stream of execution inside one process. Python gives threads a shared gate, which changes what runs truly at once and what does not.
What you will see
True
About 2 min of reading
Quick check
Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.
Try It
Check what a thread hands back.
1
Tag printed.
import threading
out = []
t = threading.Thread(target=lambda: out.append("a"))
t.start()
t.join()
print(out[0])
Before you run it, say out loud what it will print. Then open the answer.
What it prints
a
2
Threads counted.
import threading
threads = [threading.Thread(target=lambda: None) for _ in range(2)]
for t in threads:
t.start()
for t in threads:
t.join()
print(len(threads))
Before you run it, say out loud what it will print. Then open the answer.
What it prints
2
3
Workers picked.
workers = min(4, 8)
print(workers)
Before you run it, say out loud what it will print. Then open the answer.
What it prints
4
4
Cores found.
import os
print(os.cpu_count() > 0)
Before you run it, say out loud what it will print. Then open the answer.
What it prints
True
Put it in order
Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.
Data Flow
Threads are started, each runs its own stream, the gate lets one Python body at a time, and joins collect the finished work.
1start each thread
↓
2the gate picks one
↓
3each body runs
↓
4joins collect results
Line by line
Read the first example one line at a time. A line that prints shows what appears on screen; the rest set things up quietly.
import threadingsets nothing on screen
out = []sets nothing on screen
t = threading.Thread(target=lambda: out.append("a"))sets nothing on screen
t.start()sets nothing on screen
t.join()sets nothing on screen
print(out[0])a
Why this worksThe gate is one at a time
Threads let you express parallel work, but the gate lets only one run Python at a time. Measure before adding workers.
Waiting is not gated
A thread that spends its time waiting for a socket or a file is not holding the gate. That is where threads pay off in plain Python.
Examples
Two threads started
import threading
defshow(tag):
print(tag)
a = threading.Thread(target=show, args=("a",))
b = threading.Thread(target=show, args=("b",))
a.start()
b.start()
a.join()
b.join()
Both bodies run in their own stream. The join waits for each one to finish.
A thread that returns
import threading
out = []
defshow(tag):
out.append(tag)
t = threading.Thread(target=show, args=("a",))
t.start()
t.join()
print(out[0])
A thread has no return channel. The value comes back through a shared place you provide.
The gate
import threading
threads = [threading.Thread(target=lambda: None) for _ inrange(2)]
for t in threads:
t.start()
for t in threads:
t.join()
print(len(threads))
Only one thread runs Python bytecode at a time. The gate is why more threads do not mean more speed.