【问题标题】:How to avoid zombie processes in python?如何避免python中的僵尸进程?
【发布时间】:2017-08-23 11:05:42
【问题描述】:

在 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()

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

如何修改代码,让僵尸进程不存在?

【问题讨论】:

标签: python sockets zombie-process


【解决方案1】:

通常的技术是跟踪所有子 pid,以便在主进程退出或您希望清理子进程时杀死它们。

您可以根据需要定期轮询和获取进程,或者等到您即将退出。

有关如何执行此操作的示例,请查看ForkingMixin 中的collect_children() 代码以获取SocketServer module

os module 有许多用于管理子流程的工具,例如 os.wait()os.kill

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

【讨论】:

  • 但是主进程运行时间很长
  • 是的,也许这是一个合适的方式。每当创建一个新孩子时,旧的孩子就会被销毁。不是很好,但至少我不会有数百个僵尸进程......
  • @Alex 我认为这只是创建子进程时“生活中的事实”的一部分。它们需要被跟踪,没有其他工具可以自动知道你想用它们做什么。
【解决方案2】:

当一个进程退出时,它会保留在进程表中,直到有东西读取它的返回码。假设这是 linux,您可以将其设为守护进程并让 init 进程处理它。但您也可以自己致电os.waitpid。这是一个在后台等待 pid 的类的示例。它很好,因为它可以防止您的程序退出,直到它完全整理好自己。您可以将其扩展为执行诸如向子进程发送终止信号、记录结果等操作。

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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-11
    • 2019-12-31
    • 2021-11-04
    • 2011-02-15
    相关资源
    最近更新 更多