Python subprocess 完整终止子进程及进程组的方法

向北走
向北走
发布时间:2026-10-14| 3人浏览过
原创

本文介绍在Python中使用subprocess模块时,如何彻底终止由子进程派生的所有后代进程。通过设置preexec_fn为os.setpgrp创建独立进程组,并结合os.kill和os.waitpid处理信号与清理僵尸进程,解决了跨平台下的进程管理难题。

以下是本次技术调研的核心成果总结。

子进程终止的难点与进程组概念

在发布系统中,需要响应用户的中断请求。具体场景是在处理GET请求时,需要终止由subprocess模块派生的子进程。起初尝试直接使用os.kill,但发现无法杀死子进程所派生的孙子进程。经过查阅资料,了解到可以通过kill进程组来实现批量终止。然而,默认情况下,subprocess派生的进程与主程序(即当前的web.py进程)处于同一个进程组中,如果直接对该进程组发送终止信号,会导致主程序也被意外终止,这显然不符合预期。

继续查阅subprocess的官方文档,发现了一个关键参数:

subprocess.CREATE_NEW_PROCESS_GROUP 是 Popen 的 creationflags 参数,用于指定创建一个新的进程组。在使用 os.kill() 对子进程进行操作时,必须设置此标志。

需要注意的是,如果同时指定了 CREATE_NEW_CONSOLE,则该标志将被忽略。

Windows 与 Linux 下的进程组创建方案

起初认为找到了解决方案,但在实际测试中发现,该参数仅适用于 Windows 系统。考虑到 Windows 能实现的功能,Linux 系统理应也有对应的机制,于是将目光转向了 Linux 下的相关配置。

preexec_fn

再次进行搜索,原本以为需要传入一个对象,于是尝试使用 setpgid(0,0) 进行测试,但结果显示子进程仍然与主调进程属于同一个进程组。随后灵光一现,调整了参数用法。

preexec_fn = os.setpgrp

通过这种方式,成功解决了新生成进程独立成组的问题。

处理僵死进程与最终测试代码

接下来需要处理的是僵死进程(Zombie Process)的问题,通过调用 os.waitpid 即可解决。

在最初使用 waitpid 时,查阅了 Linux 手册中的相关参数说明,仍感到不放心。结果发现 Python 中的 os.waitpid 接口相对简化,参数较少且没有返回值,虽然看似简陋,但恰好满足了我的需求。

以下是经过完整测试的代码示例:

 


[liufeng@1.2.3.4 kill-subprocess]$ cat sub-process.py 
import subprocess
import os
import time

def my_func():

#派生两个子进程,子进程里又派生几个sleep的孙子进程,主要是为了测试kill进程组。

run_str2 = '/bin/sh test.sh'
run_str = '/bin/sh test_quick.sh'
cmd2 = run_str.split()
cmd = run_str.split()

#测试了一些个preexec_fn的值,最终发现能用的,对python的对象的概念还是不理解啊,新手,新手。

#p = subprocess.Popen(cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = False, creationflags = subprocess.CREATE_NEW_PROCESS_GROUP)

#p = subprocess.Popen(cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = False, creationflags = 0)

p = subprocess.Popen(cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = False, preexec_fn = os.setpgrp )

p2 = subprocess.Popen(cmd2, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = False, preexec_fn = os.setpgrp )

#@p = subprocess.Popen(cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = False, preexec_fn = os.setpgid(0, 0) )


pid = p.pid
pgid = os.getpgid(pid)
print "pid: %d\n" %pid
print "pgid: %d\n" %pgid
return pid


pid = my_func()
#p.wait()
print "now , sleep 2s ,then , os.kill gpid %d" % pid
time.sleep(20)


a = os.kill(-pid, 9)
print "kill,return:"
print a


# kill的时候,我测试了kill 没有权限的root进程,会报错:权限不允许
# 测试了kill p p2 都可以kill
#a = os.kill(2445, 9)
#print "kill root process 2445 ,return:"
#print a
#p.wait()
#os.waitpid(pgid, 0)
# 2445 is a root process
#os.waitpid(2445, 0)
#os.waitpid(p2.pid, 0)
os.waitpid(pid, 0)
print "waitpid,return:"
print a
time.sleep(22)


print "done..."


#p.terminate()
#p.kill()
#p.wait()
#
#time.sleep(40)
#os.kill(pid, 9)

以上关于 Python subprocess 彻底杀掉所有派生子进程的方法分享完毕,希望能为读者提供参考,并欢迎大家继续支持。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。