Python
multiprocessing
join method
concurrency
threading

What exactly is Python multiprocessing Module's .join Method Doing?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In Python multiprocessing, join() is a synchronization method that makes the calling process wait until another process finishes. It does not start the process, it does not fetch a return value, and it does not kill anything. Its job is simply to block until the target process exits or until an optional timeout expires.

What join() Actually Waits For

When you create a Process object and call start(), the child process begins running independently. The parent process can continue immediately unless you explicitly wait.

That is where join() comes in:

python
1from multiprocessing import Process
2import time
3
4
5def worker():
6    print("worker starting")
7    time.sleep(2)
8    print("worker done")
9
10
11p = Process(target=worker)
12p.start()
13print("parent continues")
14p.join()
15print("parent resumes after child exits")

The parent process prints parent continues, then blocks at p.join() until the worker exits. After that, execution continues.

Why join() Is Useful

Without join(), the parent may move on too early. That matters when:

  • the parent needs the child to finish before using a file or resource
  • you want orderly shutdown instead of orphaned work
  • the program should not exit before all workers finish

In other words, join() is about coordination, not about computation.

join() Does Not Return Work Results

A common misunderstanding is that join() somehow retrieves the result of the process. It does not. It only waits.

If you want data back, use an IPC mechanism such as:

  • 'Queue'
  • 'Pipe'
  • shared memory
  • a Pool result object

Example with a queue:

python
1from multiprocessing import Process, Queue
2
3
4def worker(queue):
5    queue.put(42)
6
7
8queue = Queue()
9p = Process(target=worker, args=(queue,))
10p.start()
11p.join()
12print(queue.get())

Here the queue carries the value. join() only ensures the process has finished before the parent continues.

Timeout Behavior

join() accepts an optional timeout:

python
p.join(timeout=1.5)

This waits up to 1.5 seconds. If the process is still alive afterward, join() returns anyway. It does not raise an error and it does not stop the process automatically.

To see what happened, check the process afterward:

python
1if p.is_alive():
2    print("still running")
3else:
4    print("finished")

That pattern is important when you want controlled waiting without blocking forever.

Ordering and Multiple Processes

If you have several worker processes, joining them in a loop means the parent waits for all of them before continuing:

python
1from multiprocessing import Process
2import time
3
4
5def worker(i):
6    time.sleep(i)
7    print(f"worker {i} done")
8
9
10processes = [Process(target=worker, args=(i,)) for i in [1, 2, 3]]
11
12for p in processes:
13    p.start()
14
15for p in processes:
16    p.join()
17
18print("all workers finished")

The parent does not move past the second loop until every child process has exited.

join() and Deadlocks

join() itself is simple, but it can participate in deadlocks if the child is blocked waiting for the parent and the parent is blocked in join(). This happens most often when queues, pipes, or locks are not drained or released correctly.

So the right mental model is: join() is safe, but the surrounding process design still matters.

Common Pitfalls

The most common mistake is thinking join() starts the process. The process must already have been started with start().

Another issue is assuming join() returns the function result. It does not. Use a queue, pipe, or pool result for that.

Developers also use join() with a timeout and forget to check is_alive(), which can make it look as though the child finished when it actually did not.

Summary

  • 'join() blocks the caller until the target process exits.'
  • It is a synchronization primitive, not a result-returning API.
  • Use IPC such as Queue or Pipe if you need data back from the child.
  • A timeout makes join() stop waiting, but it does not stop the child process.
  • After timed joins, check is_alive() to see whether the process actually finished.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.