python相关僵尸进程问题避免

前言

在使用Python的过程中,偶然发现进程列表出现一些defunct的字样,于是开始摸索是哪里出现问题。

僵尸进程

  僵尸进程,顾名思义,就是已经死去没有意义的进程。即⼦进程运⾏完成,但是⽗进程迟迟没有进⾏回收,此时⼦进程实际上并没有退出,其仍然占⽤着系统资源,这样的⼦进程称为僵⼫进程。
  因为僵⼫进程的资源⼀直未被回收,造成了系统资源的浪费,过多的僵⼫进程将造成系统性能下降,所以应避免出现僵⼫进程。将时间

产生僵尸进程的情况

  • 如果父进程先退出
    子进程自动被 init 进程收养,不会产生僵尸进程
  • 如果子进程先退出
    如果父进程 wait() 处理 ,则僵尸进程会被父进程清理
    如果父进程不用wait()处理,则僵尸进程会在父进程退出之前一直存在。当然,父进程退出后,僵尸子进程会被 init 收养,init 进程会自动调用 wait() 处理。但是对于处理网络请求的服务器进程来说,父进程可能会一直存在,子进程处理完任务就退出,这种情况下会产生很多僵尸进程,这种场景就需要对僵尸进程的处理提高警惕了。


如何避免产生僵尸进程

  • 推荐方法:fock twice, 用孙子进程去完成子进程的任务(注意这种方法的使用情景)
  • wait(), 但是会使父进程阻塞
  • signal(SIGCHLD,SIG_IGN), 并不是所有系统都兼容
    即主进程程序中加入一句import signalsignal.signal(signal.SIGCHLD,signal.SIG_IGN)
  • sigaction + SA_NOCLDWAIT, 并不是所有系统都兼容
  • 在signal handler中调用 waitpid ,这样父进程不用阻塞。

注意:每一种方法都有它适用的场合,比如最后一种方法适用于 one-request-one-process 的网络服务器程序,而方法 1 则不适合。

  在使用subprocess 模块的 Popen 调用外部程序时,如果调用命令,没有去等待,就会产生僵尸进程,即使你有异常捕获函数。通常我们会在调用命令之后会调用wait()函数。 这里比较推荐的做法是使用communicate()函数,而不是wait()函数。因为wait()函数,如果 stdout 或 stderr 参数是 pipe,并且程序输出超过操作系统的 pipe size时,使用Popen.wait()方式等待程序结束获取返回值,会导致死锁,程序卡在 wait() 调用上。

文章目录
  1. 1. 前言
  2. 2. 僵尸进程
    1. 2.1. 产生僵尸进程的情况
    2. 2.2. 如何避免产生僵尸进程
|
Fork me on GitHub