首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python 学习手册
Python Cookbook
Python 基础教程
Python Sites
PyPI - Python Package Index
http://www.simple-is-better.com/
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Coding
V2EX  ›  Python

subprocess 后遗症

  •  
  •   wikinee · 201 天前 · 1914 次点击
    这是一个创建于 201 天前的主题,其中的信息可能已经有所发展或是发生改变。
    用了 subprocess 的 Popen,发现主进程都退出了,子进程连用户注销之后都还能跑…

    有木有办法一块都退出了
    第 1 条附言  ·  199 天前
    总结一下这两天看的成果:
    方向一:采用钩子函数在进程退出时,发送杀死子进程。
    缺点:经过我尝试,使用 kill -9 这种做法杀死进程,可能信号都来不及发出来。如果是比较安全的环境,可以采取这种做法。(还有个缺点是,可能让某些 GUI 程序不正常,不过也可能是我个人问题)

    方向二:进程组方法
    大概也是上门类似这种钩子函数,不同的是吧子进程和主进程都放到一个进程组里面去。这是高级玩法,不太熟悉。

    方向三:放弃 subprocess,直接 shell 脚本
    反正命令也不多, 直接 cmd & 完事了。。。
    24 回复  |  直到 2019-05-30 15:05:30 +08:00
        1
    rogwan   201 天前 via Android
    你要知道进程 id 呀,主进程只负责起,不负责灭,他主进程不知道紫禁城什么时候干完活了啊。要控制的话,要进程间通讯才行
        2
    Abbeyok   201 天前
    不可能啊,主进程退出了,子进程也会强制退出啊。。
        3
    hakono   201 天前
    主进程退出的时候 Popen 调用 kill,( windows 的话 taskkill )手动杀了子进程
        4
    iyaozhen   201 天前
    一般都是父进程记录子进程的 pid,然后父进程退出时把子进程都 kill 一遍
        5
    Tink   201 天前 via iPhone
    subprocess 就是有这个问题,Popen 的时候把 pid 返回来保存,结束的时候直接杀掉
        6
    Qzier   201 天前 via iPhone
    proc = subprocess.Popen(...)
    try:
    outs, errs = proc.communicate(timeout=15)
    except TimeoutExpired:
    proc.kill()
    outs, errs = proc.communicate()
        7
    labnotok   201 天前 via Android
    手动 ps aux | grep xxx | awk '{print $2}' | kill 吧,
    我前几天用 multiprocess 的 pool 的时候出了一堆 D 进程,
    D 进程只能手动关闭,父进程 加上 兄弟进程同时关,一般就能杀掉了
        8
    tangrwx   200 天前 via iPhone
    有个参数的可以开启进程组,好像是 pexec 或者 new_session。,你可以查下文档
        9
    hhhsuan   200 天前
    用 psutil,把子进程全 kill 了:
        10
    lolizeppelin   200 天前   ♥ 1
    这些其实都不是 python 的知识
    好好把操作系统信号,和进程 fork 相关看一看

    这些基础知识不熟悉,multiprocess、subprocess 各种问题你都不知道原因,各种标准的处理方法你都不知道
    不熟悉的就不要瞎回答

    比如上面有人说这种完全错误的话

    ~~~
    不可能啊,主进程退出了,子进程也会强制退出啊。。
    ~~


    强调一下!!!这些其实都不是 python 的问题!!
        11
    lolizeppelin   200 天前
    上面的直接 kill 都不是正确做法

    如果你子进程没处理信号的话,只能用信号 9,这种做法是非常不标准的
        12
    codehz   200 天前
    Linux 平台的话,可以用 prctl PR_SET_PDEATHSIG
        13
    PTLin   200 天前
    你可以用 atexit 注册个 exit handler,然后每次 fork 的时候记录下来,调用 handler 的时候向子进程发送 SIGTERM 信号,子进程也可以注册 signal handler 来进行退出的收尾工作。
        14
    wikinee   199 天前
    @lolizeppelin 菜鸟研究的不深入,这块实在不太懂。
    @rogwan @hakono @iyaozhen @Tink 保留子进程 PID 的做法确实有效,只有一个致命缺陷,其实类似 -9 那种干掉进程的做法,有些信号什么的根本来挤不发出去,不保险。
    @tangrwx 我看了那个 prexec 什么的参数,说是 fork 之后,启动之前的一个钩子函数,然后文档里直接 NOTE 说了这个参数不保险,😅
    @Abbeyok 你可以找例子跑跑看,不要在终端 ctrl + C,试试在进程管理器里把主进程停止。
        15
    wikinee   199 天前
    @codehz @PTLin 这都是高级玩家了,我还没太深入研究这一块。
    我最后用 shell 脚本写了,放弃这种主进程、子进程的做法。
        16
    tangrwx   199 天前 via iPhone   ♥ 1
    @wikinee 试试 start_new_session 参数,其实本质是 Linux 进程组和会话的概念。
        17
    wikinee   199 天前
    @tangrwx 问题下面我补充了,我看到过这种进程组的玩法。我这边命令不多,直接写 shell 脚本了
        18
    hakono   198 天前
    @wikinee 你担心主进程被强杀的话,那你可以改变策略在子进程里监视主进程啊,主进程退出的话就退出

    如果子进程的程序不是你写的程序没法改代码加监视逻辑的话…… emmm ……
    解决办法其实有……不过算有点骚操作,你可以往子进程里注入远程代码啊哈哈哈
    在注入的代码里做主进程监视就行了,完美
        19
    lolizeppelin   198 天前
    不需要子进程监控主进程,有个很标准的做法是用管道
    主进程 fork 前开管道

    子进程开一个线程去读管道,后面紧跟强制退出代码 os._exit(1)

    因为这个读取是阻塞的,当主进程挂掉的时候阻塞读能返回空,这样就知道主进程挂了

    规范程序都按标准写法写的, 不懂把 openstack 的 luanch 那部分读透了就都明白了
        20
    PTLin   198 天前
    @wikinee 的确用 shell 实现也是很简单,cmd &放到后台,然后可以用 wait 来等待,不过我又想起来一个方法,进程 fork 后除非显式调用 setpgid 函数更改进程组 id 否则会继承父进程的进程组 id,这样父进程退出前用 kill 函数,pid 参数指定为 0 就可以发送给同一进程组的所有进程了。
        21
    butterfly1211   198 天前
    6 楼正解啊
        22
    mythmgn   196 天前
    楼主可以 wx 搜下我的号 程序员的梦呓指南 看下最近的 python 进程篇, 讲 os.system subprocess.Popen 家族裸用的原罪, 怎么处理子进程\孙子进程的问题
        24
    liuguichao   195 天前
    pgid = os.getpgid(self.proc.pid)
    os.killpg(pgid, signal.SIGTERM)
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1756 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 24ms · UTC 16:44 · PVG 00:44 · LAX 08:44 · JFK 11:44
    ♥ Do have faith in what you're doing.