python
background process
multiprocessing
threading
asynchronous

Start a background process in Python

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

"Start a background process" can mean two different things in Python. Sometimes you want to launch another program and let it keep running after your script continues. Other times you want a second Python worker process for your own code. The right tool depends on which of those jobs you actually mean.

Starting an External Program in the Background

If you want to launch another command and keep your Python script moving, use subprocess.Popen. It starts the child process immediately and returns a process object without waiting for completion.

python
1import subprocess
2import sys
3
4process = subprocess.Popen(
5    [sys.executable, "worker.py"],
6    stdout=subprocess.DEVNULL,
7    stderr=subprocess.DEVNULL,
8    start_new_session=True,
9)
10
11print(f"Started worker with PID {process.pid}")

This is the standard background-launch pattern for external commands. start_new_session=True helps detach the child from the current terminal session, which is often useful for long-running jobs.

Starting a Python Function in Another Process

If the background work is your own Python function, the multiprocessing module is usually the better fit.

python
1from multiprocessing import Process
2import time
3
4def refresh_cache():
5    for _ in range(3):
6        print("Refreshing cache...")
7        time.sleep(2)
8
9if __name__ == "__main__":
10    process = Process(target=refresh_cache)
11    process.start()
12
13    print(f"Background process started: {process.pid}")
14    print("Main program keeps running")

This creates a separate Python process with its own memory space. That is different from a thread, which shares memory with the main program.

When to Use a Thread Instead

If the task is mostly waiting on I/O, a thread may be simpler than a process. Threads are lighter to start, but they are not separate processes and do not bypass the Global Interpreter Lock for CPU-bound Python code.

That distinction matters because people often ask for a "background process" when they really mean "something that should not block the main flow." The answer might be a thread, a coroutine, a process, or an external job runner depending on the workload.

Important Process-Lifecycle Details

Background work is more than just calling start(). You should decide how the child is managed:

  • Should it die when the parent exits
  • Should its stdout and stderr be logged somewhere
  • Should the parent wait for completion later
  • Should the child be restarted if it crashes

For simple scripts, Popen or Process is enough. For production services, a process supervisor such as systemd, launchd, Docker, or a queue worker system is often a better design than trying to manage everything inside ad hoc Python code.

Common Pitfalls

The biggest mistake on Windows and macOS with spawn-based process creation is forgetting the if __name__ == "__main__" guard when using multiprocessing. Without it, the child can re-import the module and accidentally start more children.

Another mistake is assuming that Popen means fully detached. If you leave stdout and stderr connected to the terminal, the child can still be affected by the parent environment in ways that surprise you.

Be careful with shared state. Separate processes do not automatically share variables, so changes in a child do not appear in the parent unless you use IPC tools such as queues, pipes, or shared memory.

Finally, do not use a background process just to hide slow code. If the user still depends on the result immediately, all you have done is make the control flow harder to reason about.

Summary

  • Use subprocess.Popen to start an external command in the background.
  • Use multiprocessing.Process when the background job is Python code you own.
  • Use a thread instead when the task is mainly I/O-bound and separate memory is unnecessary.
  • Add the __main__ guard for safe multiprocessing startup.
  • Think about logging, shutdown, and supervision, not just how to launch the child.

Course illustration
Course illustration

All Rights Reserved.