How to Query Process Status

May 10, 2022 Python Multiprocessing

You can query the status of a multiprocessing.Process via attributes such as name, daemon and pid.

In this tutorial you will discover how to query the status of a process in Python.

Let's get started.

Need to Query Process Attributes

A process is a running instance of a computer program.

Every Python program is executed in a Process, which is a new instance of the Python interpreter. This process has the name MainProcess and has one thread used to execute the program instructions called the MainThread. Both processes and threads are created and managed by the underlying operating system.

Sometimes we may need to create new child processes in our program in order to execute code concurrently.

Python provides the ability to create and manage new processes via the multiprocessing.Process class.

You can learn more about multiprocessing in the tutorial:

An instance of the multiprocessing.Process class provides a handle of a Python process. As such, it provides attributes that we can use to query properties and the status of the underlying process.

How can we query attributes of a multiprocessing.Process instance?

How to Query Process Attributes

The multiprocessing.Process class provides instance attributes that can be used to query the status of the process.

This includes queries such as the process name and whether the process is currently alive.

The following provides a list of multiprocessing.Process attributes that we can query:

Only the "name" and "daemon" attributes can be both accessed (retrieved) and set (assigned) after the multiprocessing.Process has been instantiated. The "daemon" attribute cannot be changed after the start() function has been called to run the thread.

The "pid" attribute is read-only and returns a positive integer value after the process has started. The "exitcode" attribute is read-only and returns an integer value after the process has terminated.

The "is_alive()" function (not an attribute) returns a boolean value as to whether the read is currently executing its run() function, e.g. running, or not.

Now that we are familiar with how to query the status of a process, let's look at some examples.

Example of Querying Process Name

Each process has a name.

The parent process has the name "MainProcess".

Child processes are named automatically in a somewhat unique manner within each process with the form "Process-%d" where %d is the integer indicating the process number created by the parent process, e.g. Process-1 for the first process created.

We can access the name of a process via the multiprocessing.Process.name attribute, for example:

...
# report the process name
print(process.name)

The example below creates an instance of the multiprocessing.Process class and reports the default name of the process.

# SuperFastPython.com
# example of accessing the child process name
from multiprocessing import Process
# entry point
if __name__ == '__main__':
    # create the process
    process = Process()
    # report the process name
    print(process.name)

Running the example creates a child process and reports the default name assigned to the process.

Process-1

Example of Querying Process Daemon

A process may be a daemon.

Daemon process is the name given to the background process. By default, processes are non-daemon processes because they inherit the daemon value from the parent process, which is set False for the MainProcess.

A Python parent process will only exit when all non-daemon processes have finished exiting. For example, the MainProcess is a non-daemon process. This means that the daemon process can run in the background and do not have to finish or be explicitly excited for the program to end.

We can determine if a process is a daemon process via the multiprocessing.Process.daemon attribute.

...
# report the daemon attribute
print(process.daemon)

The example creates an instance of the multiprocessing.Process class and reports whether the process is a daemon or not.

# SuperFastPython.com
# example of assessing whether a process is a daemon
from multiprocessing import Process
# entry point
if __name__ == '__main__':
    # create the process
    process = Process()
    # report the daemon attribute
    print(process.daemon)

Running the example reports that the process is not a daemon process, the default for new child processes.

False

Example of Querying Process PID

Each process has a unique process identifier, called the PID, assigned by the operating system.

Python processes are real native processes, meaning that each process we create is actually created and managed by the underlying operating system. As such, the operating system will assign a unique integer to each thread that is created on the system (across processes).

The process identifier can be accessed via the multiprocessing.Process.pid property and is assigned after the process has been started.

...
# report the pid
print(process.pid)

The example below creates an instance of a multiprocessing.Process and reports the assigned PID.

# SuperFastPython.com
# example of reporting the native process identifier
from multiprocessing import Process
# entry point
if __name__ == '__main__':
    # create the process
    process = Process()
    # report the process identifier
    print(process.pid)
    # start the process
    process.start()
    # report the process identifier
    print(process.pid)

Running the example first creates the process and confirms that it does not have a native PID before it was started.

The process is then started and the assigned PID is reported.

Note, your PID will differ as the process will have a different identifier each time the code is run.

None
16302

Example of Querying Process Alive

A process instance can be alive or dead.

An alive process means that the run() method of the multiprocessing.Process instance is currently executing.

This means that before the start() method is called and after the run() method has completed, the process will not be alive.

We can check if a process is alive via the multiprocessing.Process.is_alive() method.

...
# report the process is alive
print(process.is_alive())

The example below creates a multiprocessing.Process instance then checks whether it is alive.

# SuperFastPython.com
# example of assessing whether a process is alive
from multiprocessing import Process
# entry point
if __name__ == '__main__':
    # create the process
    process = Process()
    # report the process is alive
    print(process.is_alive())

Running the example creates a new multiprocessing.Process instance then reports that the process is not alive.

False

We can update the example so that the process sleeps for a moment and then reports the alive status of the process while it is running.

This can be achieved by setting the "target" argument to the multiprocessing.Process to execute a custom function that sleeps for one second.

First, we can define the function.

# function to execute in a new process
def task():
    sleep(1)

Then we can create a new process instance and configure it to execute our function in a new thread.

...
# create the process
process = Process(target=task)

We can then start the process by calling the start() function and report the alive status of the process while it is running.

...
# start the process
process.start()
# report the process is alive
print(process.is_alive())

Finally, we can wait for the process to finish and report the status of the process afterward.

...
# wait for the process to finish
process.join()
# report the process is alive
print(process.is_alive())

Tying this together, the complete example of checking the alive status of a process while it is running is listed below.

# SuperFastPython.com
# example of assessing whether a running process is alive
from time import sleep
from multiprocessing import Process

# function to execute in a new process
def task():
    sleep(1)

# entry point
if __name__ == '__main__':
    # create the process
    process = Process(target=task)
    # report the process is alive
    print(process.is_alive())
    # start the process
    process.start()
    # report the process is alive
    print(process.is_alive())
    # wait for the process to finish
    process.join()
    # report the process is alive
    print(process.is_alive())

Running the example creates the process instance and confirms that it is not alive before the start() function has been called.

The process is then started and blocked for a second, meanwhile we check the alive status in the parent process which is reported as True, the thread is alive.

The process finishes and the alive status is reported again, showing that indeed the process is no longer alive.

False
True
False

Example of Querying Process Exit Code

A child process will have an exit code once it has terminated.

An exit code provides an indication of whether processes completed successfully or not, and if not, the type of error that occurred that caused the termination.

Common exit codes include:

We can write the exit code for a child process via the multiprocessing.Process.exitcode attribute.

...
# report the process exit code
print(process.exitcode)

A process will not have an exit code until the process is terminated. This means, checking the exit code of a process before it has started or while it is running will return a None value.

We can demonstrate this with a worked example that executes a custom target function that blocks for one second.

First, we create a new process instance to execute our task() function, report the exit code, then start the process and report the exit code while the process is running.

...
# create the process
process = Process(target=task)
# report the exit status
print(process.exitcode)
# start the process
process.start()
# report the exit status
print(process.exitcode)

We can then block until the child process has terminated, then report the exit code.

...
# wait for the process to finish
process.join()
# report the exit status
print(process.exitcode)

Tying this together, the complete example is listed below.

# SuperFastPython.com
# example of checking the exit status of a child process
from time import sleep
from multiprocessing import Process

# function to execute in a new process
def task():
    sleep(1)

# entry point
if __name__ == '__main__':
    # create the process
    process = Process(target=task)
    # report the exit status
    print(process.exitcode)
    # start the process
    process.start()
    # report the exit status
    print(process.exitcode)
    # wait for the process to finish
    process.join()
    # report the exit status
    print(process.exitcode)

Running the example first creates a new process to execute our custom task function.

The status code of the child process is reported, which is None as expected. The process is started and blocked for one second. While running, the exit code is reported again, which again is None as expected.

The parent process then blocks until the child process terminates. The exit code is reported, and in this case we can see that a value of zero is reported indicating a normal or successful exit.

None
None
0

The exit code for a process can be set by calling sys.exit() and specifying an integer value, such as 1 for a non-successful exit.

We can demonstrate this with a worked example where our custom task() function exits with a failure.

The updated task() function with this change is listed below.

# function to execute in a new process
def task():
    # block for a moment
    sleep(1)
    # exit with an error
    sys.exit(1)

We can then create and start the process and wait for it to terminate

...
# create the process
process = Process(target=task)
# start the process
process.start()
# wait for the process to finish
process.join()

Once terminated, we can report the exit code.

...
# report the exit status
print(process.exitcode)

Tying this together, the complete example is listed below.

# SuperFastPython.com
# example of checking the exit status of a child process
from time import sleep
from multiprocessing import Process
import sys

# function to execute in a new process
def task():
    # block for a moment
    sleep(1)
    # exit with an error
    sys.exit(1)

# entry point
if __name__ == '__main__':
    # create the process
    process = Process(target=task)
    # start the process
    process.start()
    # wait for the process to finish
    process.join()
    # report the exit status
    print(process.exitcode)

Running the example first creates and starts the new process.

The child process blocks for a moment, then exits with a failure status.

The parent process blocks until the child process is finished, then reports the exit code, which is 1 indicating a failure in this case.

1

Takeaways

You now know how to query the attributes of a process instance.



If you enjoyed this tutorial, you will love my book: Python Multiprocessing Jump-Start. It covers everything you need to master the topic with hands-on examples and clear explanations.