Skip to content

Creating and Starting Threads

diagram start() runs it elsewhere; run() just calls it mermaid
Thread.run is the ordinary method holding your target. Calling it yourself executes the body on whatever thread you called it from, which means no concurrency at all and no error to tell you. start() is the one that asks the operating system for a thread and then invokes run there.
basic_thread.py
import threading
 
 
def greet(name: str) -> None:
    print("Hello", name)
 
 
t = threading.Thread(target=greet, args=("Ravi",))
t.start()
t.join()
print("Main thread finished")

Naming is helpful for logs.

thread_name.py
import threading
 
 
def work():
    print("Running in:", threading.current_thread().name)
 
 
t = threading.Thread(target=work, name="worker-1")
t.start()
t.join()

If you don’t join(), the main program may exit early in some cases.

Threads share memory. You need locks (next pages).

sketch start() puts the work elsewhere; run() does not p5.js
Two launches of the same target, which reports the thread it is executing on. With start() the work lands on a new thread and the main thread carries on immediately. With run() it is an ordinary method call, so the body executes on the caller and main waits for it -- no error, no warning, and no concurrency.
pch.quizTag pch.quizDefaultTitle
  1. You call `t.run()` instead of `t.start()`. What happens?

    pch.quizShowAnswer

    B — The target runs on the calling thread — no concurrency, no error — Verified by asking the target which thread it was on: `start()` reported `Thread-1`, `run()` reported `MainThread`. Nothing raises, so the program looks correct and is simply sequential.

  2. What does calling `start()` on a thread that has already finished do?

    pch.quizShowAnswer

    C — Raises RuntimeError: threads can only be started once — Verified. A Thread object is single-use — create a new one per run.

  3. How do you reliably know a worker thread has finished?

    pch.quizShowAnswer

    B — Call `t.join()`, then `t.is_alive()` is False — `join()` waits; `is_alive()` confirms. There is no `stop()` — a thread must be asked to finish, usually by checking a `threading.Event`.

  4. Why does threading often fail to speed up CPU-bound Python?

    pch.quizShowAnswer

    B — The GIL lets only one thread run Python bytecode at a time — Measured elsewhere in this course: CPU-bound work on a 4-thread pool came out at 0.92x — slower than sequential. I/O-bound work on the same pool reached 9.2x, because a waiting thread releases the GIL.

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading