Overview
To determine if a process created with multiprocessing is currently running or has already finished, you can use the is_alive() method. By also checking the process ID (pid) and the exitcode, you can manage the status of your processes in detail. This article explains how to monitor multiple asynchronous processes using a monitoring loop in the main process.
Specifications (Input/Output)
- Input: A generated
multiprocessing.Processobject. - Output:
is_alive(): ReturnsTrueif the process is running, otherwiseFalse(not started or finished).pid: The process ID (valid only while running).exitcode: The exit code (valid only after finishing.0indicates normal termination).
- Behavior: The main process runs a loop to poll (query) the status of each sub-process at regular intervals and displays the results.
Basic Usage
Call the method on the process object.
if process.is_alive():
print(f"Running (PID: {process.pid})")
else:
print(f"Finished (ExitCode: {process.exitcode})")
Full Code Example
The following code starts two processes with different execution times and continues to report their status from the main process until both have finished.
import multiprocessing
import time
import os
import random
def worker_task(name: str, duration: int):
"""
A task that runs for a specified duration.
"""
print(f" [{name}] Started (PID: {os.getpid()}) Duration: {duration}s")
# Simulate processing
for i in range(duration):
time.sleep(1)
print(f" [{name}] Finished")
def main():
print("--- Main Process Started ---")
# Create two processes with different durations
# process1: Finishes in 3 seconds
p1 = multiprocessing.Process(
target=worker_task,
kwargs={"name": "Process-1", "duration": 3}
)
# process2: Finishes in 6 seconds
p2 = multiprocessing.Process(
target=worker_task,
kwargs={"name": "Process-2", "duration": 6}
)
# Start the processes
p1.start()
p2.start()
# Monitoring loop
# Continue the loop as long as at least one process is alive
while p1.is_alive() or p2.is_alive():
print(f">>> Monitoring: P1={p1.is_alive()}, P2={p2.is_alive()}")
if not p1.is_alive() and p1.exitcode is not None:
print(f" (P1 has finished. ExitCode: {p1.exitcode})")
time.sleep(1.0)
print("--- All processes finished detected ---")
# Resource cleanup (join should be called even if is_alive is False to prevent zombies)
p1.join()
p2.join()
print("All tasks are complete.")
if __name__ == "__main__":
main()
Example Output
You can see that Process-1 finishes first, followed by Process-2.
--- Main Process Started ---
[Process-1] Started (PID: 12345) Duration: 3s
[Process-2] Started (PID: 12346) Duration: 6s
>>> Monitoring: P1=True, P2=True
>>> Monitoring: P1=True, P2=True
>>> Monitoring: P1=True, P2=True
[Process-1] Finished
>>> Monitoring: P1=False, P2=True
(P1 has finished. ExitCode: 0)
>>> Monitoring: P1=False, P2=True
(P1 has finished. ExitCode: 0)
[Process-2] Finished
--- All processes finished detected ---
All tasks are complete.
Customization Points
- Adjusting the Polling Interval: Shortening the
time.sleep(1.0)value makes detection faster but increases CPU load. Adjust this according to your needs. - Changing Monitoring Conditions:
while p1.is_alive() or p2.is_alive():waits while at least one process is running.- Changing it to
andwill loop only while both are running, exiting the loop as soon as one finishes.
- Forced Termination: If a process takes too long, you can add logic to call
process.terminate()to force it to stop.
Important Notes
- Importance of join(): Even if
is_alive()becomesFalse, process information remains in memory untiljoin()is called (this is known as a zombie process). Always executejoin()after the monitoring loop. - Status Before start():
is_alive()returnsFalseimmediately after the process instance is created (beforestart()). Be careful to distinguish between “not yet started” and “already finished.” - Exitcode Timing: While the process is running,
exitcodeisNone. It only receives an integer value once the process has finished.
Advanced Application
This pattern uses join(timeout) for non-blocking waiting. Instead of manually sleeping in a while loop, you use the timeout feature of join to repeat the action: “wait until finished or until the specified time has passed.”
import multiprocessing
import time
def task():
time.sleep(2)
if __name__ == "__main__":
p = multiprocessing.Process(target=task)
p.start()
# Repeat until the process ends
while p.is_alive():
print("Still running...")
# Wait for 0.5 seconds. Returns immediately if finished.
p.join(timeout=0.5)
print("Finished")
Conclusion
Using is_alive() allows you to visualize the progress of parallel processing, which can otherwise be a “black box.”
Reminder: Calling join() to release resources is mandatory even after monitoring is finished. By actively checking the status instead of just waiting with p.join(), you can implement advanced and responsive parallel processing workflows.
Best for: Displaying progress bars, health monitoring, or starting the next task as soon as one process ends.
Key Point: Configure the monitoring loop condition (or vs and) based on your specific requirements.
