本文旨在解决 Python 程序内命令行子进程的问题。
首先需要总结一下 windows 和 linux 分别的 shell 命令,包括端口,进程,PID 等。
最后比较内置库 subprocessing
和第三方库 psutil
,然后分别实现 Python 控制子进程的 demo。
netstat
是通用命令,但是参数不同
windows 使用 -ano
参数,代表 all & numerical & owning pid
,这里的 -n
指用的是纯数字地址,不用电脑的名字去替换 0.0.0.0
这种特殊地址
Linux 使用 -tunlp
参数,代表 tcp udp numerical listen PID/Program
,这里的 -n
和 Windows 一样
如果要找到特定的端口,Windows 使用 findstr
命令
`netstat -ano | findstr "8000" `
Linux 使用 grep
即可
Linux 使用 ps -aux
命令,第二列就是 PID
Windows 使用 tasklist
命令,第二列就是 PID
这里不讲 Linux —— Linux 在 Python 中可以直接抓住 PID,Windows 抓不住才要说
首先我们用 python.exe
运行 .py
文件,.py
文件内容如下,是个不断输出 yes
的程序
使用 wmic
命令如下,可以找到相关 Commandline
和 PID
wmic process where "name='python.exe'" get processid,commandline
反过来也可以通过 PID 查询进程相关信息
wmic process where "ProcessId='6752'" get processid,commandline
Linux 使用 kill <pid>
命令瞄准 PID 杀死进程,强制杀死使用 kill -9 <pid>
,这里涉及到 linux signals
,明天专门写一篇 linux signals 来阐述其中原理
Windows 使用 taskkill /T /F /PID <pid>
来瞄准 PID 杀死进程,使用 taskkill /?
可以查看命令的相关内容,其中这三个参数的意思如下
`/T Terminates the specified process and any child processes which were started by it. /F Specifies to forcefully terminate the process(es). /PID Specifies the PID of the process to be terminated. `
即 terminate force pid
,就是强制终止该 PID 对应的进程以及所有子进程
第一种方案是内置库 subprocess
,第二种方案是第三方库 psutil
第三方库无疑是建立在内置库的基础上做了一些封装的,在没有一些非常定制化的需求时,可以完全胜任我们的任务。但是我倾向于搞懂底层原理,为了防止以后有更牛逼的第三方库出现时我不知所云。
我们现在来执行一个 .py
文件以子进程的方式执行另一个 .py
文件
`""" Use subprocess.Popen and psutil.Popen to start subprocess """ import re import time from typing import Optional import subprocess import psutil class SayYesController: def __init__(self) -> None: self.file = "say_yes.py" self.pid : Optional[str] = None def open_sub_by_subprocess(self): command = f"python {self.file}" subprocess.Popen(command,shell=True) def get_pid_by_subprocess(self): command = """wmic process where "name='python.exe'" get processid,commandline""" subprocess_info_block = subprocess.check_output(command,shell=True) print(subprocess_info_block) for info in str(subprocess_info_block).split(r'\n'): if "say_yes.py" in info: self.pid = re.findall('(\d+)',info)[0] print("Parsed PID is",self.pid) break def kill_pid_by_subprocess(self): if self.pid is None: return subprocess.call(f'taskkill /T /F /PID {self.pid}',shell=True) def test_subprocess(self): self.open_sub_by_subprocess() time.sleep(10) self.get_pid_by_subprocess() self.kill_pid_by_subprocess() def test_psutil(self): process = psutil.Popen(f"python {self.file}") time.sleep(10) process.terminate() def run(self): print("===== test subprocessing =====") self.test_subprocess() print("===== test psutil =====") self.test_psutil() if __name__ == "__main__": bot = SayYesController() bot.run() `
运行的结果是都成功了,但是前一种方法是真的很费时费力,后面只要一个 .terminate()
就自动帮你找到进程然后杀死了
今天总结了 Windows 和 Linux 的端口,进程,PID 的命令,然后使用 Python 交互了一下命令行,发现就找到 PID 然后杀死对应进程这一件事来说,psutil
确实是大大减少了我们的时间花费
对了,最后的最后我们看一下 Mac 和 Linux 是怎么搞出进程号的
`p = subprocess.Popen('python test.py', shell=True) p = p.pid `
哈哈是可以直接搞到 PID 的。又是对 Windows 无奈的一天,不过现在有 psutils
库,这也不是事儿啦!
更多每日开发小技巧
尽在****未闻 Code Telegram Channel !
END
未闻 Code·知识星球开放啦!
一对一答疑爬虫相关问题
职业生涯咨询
面试经验分享
每周直播分享
......
未闻 Code·知识星球期待与你相见~
一二线大厂在职员工
十多年码龄的编程老鸟
国内外高校在读学生
中小学刚刚入门的新人
在“未闻 Code技术交流群”等你来!
入群方式:添加微信“mekingname”,备注“粉丝群”(谢绝广告党,非诚勿扰!)