ZetCode

Python os.getppid 函数

上次修改时间:2025 年 4 月 11 日

这个全面的指南探讨了 Python 的 os.getppid 函数,它返回当前进程的父进程 ID (PPID)。我们将介绍进程层级、实践示例和相关的系统调用。

基本定义

os.getppid 函数返回创建当前进程的父进程的进程 ID。每个进程(除了 init 进程)在类 Unix 系统中都有一个父进程。

要点:返回整数 PPID,在 Unix/Windows 上可用,与 os.getpid(当前 PID)相关。父进程可以在子进程继续运行的同时终止(孤儿进程)。

基本用法示例

这个简单的例子演示了如何使用 os.getpidos.getppid 获取当前进程 ID 和它的父进程 ID。

basic_usage.py
import os

print(f"Current process ID (PID): {os.getpid()}")
print(f"Parent process ID (PPID): {os.getppid()}")

直接运行时,这将显示 Python 解释器的 PID 和启动它的终端/shell 的 PID。每次运行的输出都会有所不同。

父进程通常是执行 Python 脚本的 shell 或进程。这种关系形成一个进程树层级。

进程层级演示

这个例子创建了一个子进程来展示父子关系如何工作,以及 PPID 如何在子进程中改变。

process_hierarchy.py
import os
import time

def child_process():
    print(f"Child PID: {os.getpid()}")
    print(f"Child's PPID: {os.getppid()}")
    time.sleep(2)

def parent_process():
    print(f"Parent PID: {os.getpid()}")
    print(f"Parent's PPID: {os.getppid()}")
    
    pid = os.fork()
    if pid == 0:  # Child process
        child_process()
    else:  # Parent process
        print(f"Created child with PID: {pid}")
        time.sleep(3)

if __name__ == "__main__":
    parent_process()

这个特定于 Unix 的例子使用 os.fork 创建一个子进程。子进程报告它的 PID 和 PPID(即父进程的 PID)。

请注意,Windows 不支持 os.fork - 这个例子仅在类 Unix 系统上有效。sleep 调用防止过早退出。

孤儿进程检测

这个例子演示了如何检测父进程何时死亡,使子进程成为孤儿(被 init 进程收养,PPID 变为 1)。

orphan_process.py
import os
import time

def child_process():
    original_ppid = os.getppid()
    print(f"Child started with PPID: {original_ppid}")
    
    while True:
        current_ppid = os.getppid()
        if current_ppid != original_ppid:
            print(f"Parent died! New PPID: {current_ppid}")
            break
        time.sleep(1)

def parent_process():
    print(f"Parent PID: {os.getpid()}")
    pid = os.fork()
    if pid == 0:  # Child
        child_process()
    else:  # Parent
        time.sleep(2)
        print("Parent exiting")

if __name__ == "__main__":
    parent_process()

子进程持续检查它的 PPID。当父进程退出时,子进程的 PPID 变为 1(Unix 系统上的 init 进程)。

这演示了进程如何比它们的父进程活得更久,以及系统如何重新分配孤儿进程以维护进程层级。

跨平台进程创建

这个例子展示了一种跨平台的方式来创建进程并使用 os.getppid 检查父子关系。

cross_platform.py
import os
import sys
import time
from multiprocessing import Process

def child_task():
    print(f"Child PID: {os.getpid()}")
    print(f"Child's PPID: {os.getppid()}")
    time.sleep(2)

if __name__ == "__main__":
    print(f"Parent PID: {os.getpid()}")
    
    # Cross-platform process creation
    p = Process(target=child_task)
    p.start()
    
    print(f"Created child with PID: {p.pid}")
    p.join()
    print("Parent exiting")

使用 multiprocessing.Process 而不是 os.fork 使其在 Unix 和 Windows 系统上都能工作,同时保持父子关系。

子进程报告它的 PID 和 PPID,显示与创建它的父进程的关系。

进程树可视化

这个例子通过递归地创建子进程并跟踪父子关系来构建一个简单的进程树。

process_tree.py
import os
import time
from multiprocessing import Process

def process_node(name, depth):
    if depth <= 0:
        return
        
    print(f"{'  '*(3-depth)}Node {name}: PID={os.getpid()}, PPID={os.getppid()}")
    
    children = []
    for i in range(2):  # Create 2 child processes
        p = Process(target=process_node, args=(f"{name}.{i}", depth-1))
        children.append(p)
        p.start()
    
    time.sleep(1)  # Wait for children to print their info
    
    for p in children:
        p.join()

if __name__ == "__main__":
    process_node("root", 3)

这创建了一个深度为 3 级的进程二叉树,打印每个进程的 PID 和 PPID 以可视化层级结构。

输出中的缩进有助于可视化树结构。每个进程都通过 os.getppid 知道它的父进程。

守护进程示例

这个例子演示了守护进程如何维护它们的 PPID 关系,以及它与常规进程的不同之处。

daemon_process.py
import os
import time
from multiprocessing import Process

def daemon_task():
    print(f"Daemon PID: {os.getpid()}, PPID: {os.getppid()}")
    while True:
        print(f"Daemon running (PPID: {os.getppid()})")
        time.sleep(1)

if __name__ == "__main__":
    print(f"Main PID: {os.getpid()}")
    d = Process(target=daemon_task, daemon=True)
    d.start()
    
    print(f"Created daemon with PID: {d.pid}")
    time.sleep(3)
    print("Main process exiting (daemon will terminate)")

守护进程被设计为在它们的父进程退出时终止。这个例子显示了执行前后 PPID 关系。

与孤儿进程示例不同,守护进程不会被重新分配给 init 进程 - 它们在它们的父进程退出时终止。

安全注意事项

最佳实践

资料来源

作者

我叫 Jan Bodnar,我是一位热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 至今,我已撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程