主进程功能
- 启动 3 个子进程
- 采集子进程所有输出
- 检测 子进程状态 ,某个子进程状态变化时,打印 <子程pid> stat:
- 子进程全部退出时,退出主进程
子进程功能
- 存活期间定时输出 ,10s 输出一次 sleep module: eventlet.greenthread
- 当被非强制 终止时,嘲讽一下,"i do not want be kill ! you can not kill me ! hahaha !\n"
- 被强制终止时,退出
使用方法
在另外一个终端中操控子进程
# 查看 所有 存活 子进程信息
ps -aux|grep capture_process |grep -v grep
root 97475 0.1 0.1 190000 9940 pts/0 S+ 00:29 0:00 python ./capture_process.py 2>&1
root 97476 0.1 0.1 190000 9940 pts/0 S+ 00:29 0:00 python ./capture_process.py 2>&1
# 发送 非强制性 终止信号
ps -aux|grep capture_process | grep -v grep|awk '{print $2}'|xargs kill
# 发送 强制性 终止信号
ps -aux|grep capture_process | grep -v grep|awk '{print $2}'|xargs kill -9
# 根据查询到的 信息,的pid 控制其中一个
## 非强制
kill 97475
## 强制
kill -9 [pid]
简单测试
cd 到项目目录,
pip 安装好 eventlet
# 启动主进程
# 主进程可以被正常 crtl c
python proc_manager.py
打开另外一个终端 输入
ps -aux|grep capture_ | grep -v grep|awk '{print $2}'|xargs kill
发现主进程终端会显示
i do not want be kill ! you can not kill me ! hahaha !
i do not want be kill ! you can not kill me ! hahaha !
i do not want be kill ! you can not kill me ! hahaha !
输入
ps -aux|grep capture_ | grep -v grep|awk '{print $2}'|xargs kill -9
发现主进程终端
退出
[root@localhost ~]# ps -aux|grep capture_ | grep -v grep|awk '{print $2}'|xargs kill -9
[root@localhost ~]#
实验观察
根据 操控子进程提示,退出一个 子进程观察 主进程输出 再退出 1 个, 再退出 1 个
capture_process.py
#!/usr/bin/python
# -*- encoding: utf-8 -*-
'''
@File : capture_process.py
@Time : 2021/01/29 09:31:18
@Author : lmk
@Version : 1.0
@Contact : lmk@zettakit.com
@Purpose : mock one process can be terminate
'''
# import signal
# signal.SIGABORT
# signal.SIGHUP # 连接挂断
# signal.SIGILL # 非法指令
# signal.SIGINT # 连接中断
# signal.SIGKILL # 终止进程(此信号不能被捕获或忽略)
# signal.SIGQUIT # 终端退出
# signal.SIGTERM # 终止
# signal.SIGALRM # 超时警告
# signal.SIGCONT # 继续执行暂停进程
import signal,time
import sys
import eventlet
eventlet.monkey_patch()
from eventlet import sleep
def term_sig_handler(signum,frame):
std_print("i do not want be kill ! you can not kill me ! hahaha !\n")
def std_print(*args):
s = " ".join(args)+"\n"
sys.stdout.write(s)
sys.stdout.flush()
# ps -aux|grep capture_process | grep -v grep|awk '{print $2}'|xargs kill -9
# ps -aux|grep capture_process | grep -v grep
if __name__ == "__main__":
signal.signal(signal.SIGTERM,term_sig_handler)
signal.signal(signal.SIGINT,term_sig_handler)
std_print("start")
while True:
std_print("sleep module:",sleep.__module__ )
sleep(10)
std_print("end")
proc_manager.py
#!/usr/bin/python
# -*- encoding: utf-8 -*-
'''
@File : process.py
@Time : 2021/01/28 17:03:10
@Author : lmk
@Version : 1.0
@Contact : lmk@zettakit.com
@Purpose :
'''
import sys
import subprocess as sp
import eventlet
eventlet.monkey_patch()
from eventlet import spawn,spawn_after,sleep
import eventlet.debug
# eventlet.debug.hub_prevent_multiple_readers(False)
# RuntimeError: Second simultaneous read on fileno 6 detected. Unless you really know what you're doing, make sure that only one greenthread can read any particular socket. Consider using a pools.Pool. If you do know what you're doing and want to disable this error, call eventlet.debug.hub_prevent_multiple_readers(False) - MY THREAD=<built-in method switch of GreenThread object at 0x7fbd883d1050>; THAT THREAD=FdListener('read', 6, <built-in method switch of GreenThread object at 0x7fbd883b60f0>, <built-in method throw of GreenThread object at 0x7fbd883b60f0>)
m_ver = sys.version.split(".")[0]
_out = sys.stdout.write
class VolumeProcessManager(object):
def __init__(self):
self._proc_dict = {}
self.run_subprocs()
self.get_all_subp_out()
self.real_kill_all()
self.wait_all()
# self.x = input()
def get_backends_conf(self):
return range(3)
def run_subprocs(self):
list(map(self.run_subproc, self.get_backends_conf()))
def run_subproc(self, cmd):
params ={
"stdout":sp.PIPE ,
"stderr":sp.STDOUT,
"universal_newlines":True
}
# if m_ver == '3':
# params.update({ "text":True})
p = sp.Popen(["python","./capture_process.py","2>&1"], **params)
self._proc_dict[p.pid] = p
print("pid: ",p.pid)
# p.terminate()
def wait_all(self):
_p_statues = {}
while True:
# None 代表未 全部 退出 ,1 代表 所有sub p退出
all_code = 1
for p in self._proc_dict.values():
ret_code = p.poll()
if _p_statues.get(p.pid,"null") != ret_code:
_p_statues[p.pid] = ret_code
_out("{} stat: {}\n".format(p.pid,ret_code))
if ret_code ==None:
# 代表 子进程还在运行
all_code = None
# 其实此时就可以终止判断, 但是为了 更好地体验交互,就不提前退出了
# break
if all_code != None:
break
sleep(1)
# [p.wait() for p in self._proc_dict.values()]
def get_all_subp_out(self):
def f():
for p in self._proc_dict.values():
self.get_subp_out(p)
spawn(f)
def real_kill_all(self):
# sleep(1)
for p in self._proc_dict.values():
spawn(self.real_kill,p)
# self.real_kill(p)
@staticmethod
def get_subp_out(p):
def read_line(p):
while True:
out = p.stdout.readline()
_out(out)
sleep(1)
spawn(read_line,p)
@staticmethod
def real_kill(p):
def force_kill(p):
if p.poll() == None:
p.kill()
p.terminate()
spawn_after(3,force_kill,p)
if __name__ == "__main__":
VolumeProcessManager()