如何避免python中的僵尸进程?

时间:2017-03-29 19:18:37

标签: python sockets zombie-process

在Python3中,我基本上有以下代码:

server.py:

import os
import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(("127.0.0.1", 10000))
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.listen(5)

while True:
    print("waiting")
    connection, client_address = sock.accept()
    print("received")
    child_pid = os.fork()
    if child_pid == 0:
        print("connection received")
        received = connection.recv(1024)
        connection.sendall("OK".encode('utf-8'))
        os._exit(0)

client.py:

import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("127.0.0.1", 10000))    
sock.close()

当我启动服务器然后启动客户端时,每次客户端完成僵尸进程时都会保留。

如何更改代码,以便不再保留僵尸进程?

2 个答案:

答案 0 :(得分:3)

通常的技巧是跟踪所有的儿童按钮,以便在主要进程退出时或者您希望清理儿童时将其杀死。

您可以根据需要定期轮询和收听流程,或等到您即将退出。

有关如何执行此操作的示例,请查看collect_children()ForkingMixinSocketServer module代码。

os module有许多工具可用于管理os.wait()os.kill等子流程。

我不知道它是否适合您的问题,但multiprocessing.Pool()可能会有所帮助。它自动管理子进程池并将其重用于将来的任务。当进程之间只有有限的数据交换以及工作是否相对同质(所有子进程都在做同样的工作)时,它主要是有用的。

答案 1 :(得分:0)

当进程退出时,它会保留在进程表中,直到某些内容读取其返回代码。假设这是linux,你可以让它成为守护进程并让init进程处理它。但你也可以自己打电话给os.waitpid。以下是在后台等待pids的类的示例。它很好,因为它可以让你的程序退出,直到完全整理它为止。您可以将其扩展为执行诸如向子进程发送终止信号,记录结果等等。

import threading
import queue
import os
import time

class ZombieKiller(threading.Thread):
    """Okay, really its just a zombie waiter, but where's the fun in that?
    """
    def __init__(self):
        super().__init__()
        self.pid_q = queue.Queue()
        self.start()

    def run(self):
        while True:
            pid = self.pid_q.get()
            if pid is None:
                return
            print(pid, 'wait')
            os.waitpid(pid, 0)
            print(pid, 'wait done')

    def cull_zombie(self, pid):
        self.pid_q.put(pid)

    def close(self):
        self.pid_q.put(None)
        self.join()

def test():
    zombie_killer = ZombieKiller()
    for i in range(3):
        pid = os.fork()
        if pid == 0:
            # child
            time.sleep(5)
            print(os.getpid(), 'work done')
            exit()
        else:
            # parent
            zombie_killer.cull_zombie(pid)
    zombie_killer.close()
    print('test complete')


test()