how to kill (or avoid) zombie processes with subprocess module

后端 未结 9 1161
悲&欢浪女
悲&欢浪女 2020-11-29 22:10

When I kick off a python script from within another python script using the subprocess module, a zombie process is created when the subprocess \"completes\". I am unable to

相关标签:
9条回答
  • 2020-11-29 22:55

    A zombie process is not a real process; it's just a remaining entry in the process table until the parent process requests the child's return code. The actual process has ended and requires no other resources but said process table entry.

    We probably need more information about the processes you run in order to actually help more.

    However, in the case that your Python program knows when the child processes have ended (e.g. by reaching the end of the child stdout data), then you can safely call process.wait():

    import subprocess
    
    process= subprocess.Popen( ('ls', '-l', '/tmp'), stdout=subprocess.PIPE)
    
    for line in process.stdout:
            pass
    
    subprocess.call( ('ps', '-l') )
    process.wait()
    print "after wait"
    subprocess.call( ('ps', '-l') )
    

    Example output:

    $ python so2760652.py
    F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
    0 S   501 21328 21326  0  80   0 -  1574 wait   pts/2    00:00:00 bash
    0 S   501 21516 21328  0  80   0 -  1434 wait   pts/2    00:00:00 python
    0 Z   501 21517 21516  0  80   0 -     0 exit   pts/2    00:00:00 ls <defunct>
    0 R   501 21518 21516  0  80   0 -   608 -      pts/2    00:00:00 ps
    after wait
    F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
    0 S   501 21328 21326  0  80   0 -  1574 wait   pts/2    00:00:00 bash
    0 S   501 21516 21328  0  80   0 -  1467 wait   pts/2    00:00:00 python
    0 R   501 21519 21516  0  80   0 -   608 -      pts/2    00:00:00 ps
    

    Otherwise, you can keep all the children in a list, and now and then .poll for their return codes. After every iteration, remember to remove from the list the children with return codes different than None (i.e. the finished ones).

    0 讨论(0)
  • 2020-11-29 22:56

    The python runtime takes responsibility for getting rid of zombie process once their process objects have been garbage collected. If you see the zombie lying around it means you have kept a process object and not called wait, poll or terminate on it.

    0 讨论(0)
  • 2020-11-29 22:57

    I'm not sure what you mean "I need to run my script with no_wait()", but I think this example does what you need. Processes will not be zombies for very long. The parent process will only wait() on them when they are actually already terminated and thus they will quickly unzombify.

    #!/usr/bin/env python2.6
    import subprocess
    import sys
    import time
    
    children = []
    #Step 1: Launch all the children asynchronously
    for i in range(10):
        #For testing, launch a subshell that will sleep various times
        popen = subprocess.Popen(["/bin/sh", "-c", "sleep %s" % (i + 8)])
        children.append(popen)
        print "launched subprocess PID %s" % popen.pid
    
    #reverse the list just to prove we wait on children in the order they finish,
    #not necessarily the order they start
    children.reverse()
    #Step 2: loop until all children are terminated
    while children:
        #Step 3: poll all active children in order
        children[:] = [child for child in children if child.poll() is None]
        print "Still running: %s" % [popen.pid for popen in children]
        time.sleep(1)
    
    print "All children terminated"
    

    The output towards the end looks like this:

    Still running: [29776, 29774, 29772]
    Still running: [29776, 29774]
    Still running: [29776]
    Still running: []
    All children terminated
    
    0 讨论(0)
提交回复
热议问题