2017-03-29 4 views
3

En python3, j'ai essentiellement le code suivant:Comment éviter les processus zombies en python?

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

Quand je démarre le serveur et le client, chaque fois le client termine un processus de zombie reste. Comment changer le code afin qu'il ne reste aucun processus zombie?

+0

[question similaire] (http://stackoverflow.com/questions/2760652/how-to-kill- ou-avoid-zombie-processes-with-subprocess-module), celui-ci utilisant le module ['subprocess'] (https://docs.python.org/3/library/subprocess.html) au lieu d'essayer de gérer l'enfant discussions directement. –

+0

S'agit-il en effet de [zombies] (https://en.wikipedia.org/wiki/Zombie_process), c'est-à-dire des processus à l'état terminé? Peut-être qu'ils sont en vie, juste perdu le processus parent? – 9000

+2

Ceci est un [doublon de cette question] (https://stackoverflow.com/questions/18090230/forking-python-defunct-child) – user2722968

Répondre

2

La technique habituelle consiste à suivre tous les pids enfants afin qu'ils puissent être tués lorsque le processus principal se termine ou quand vous voulez que les enfants soient nettoyés.

Vous pouvez périodiquement interroger et récolter des processus si nécessaire ou attendre jusqu'à ce que vous soyez sur le point de quitter.

Pour un exemple de la façon de procéder, regardez le code collect_children() dans le ForkingMixin pour le SocketServer module.

Le os module dispose d'un certain nombre d'outils pour gérer les sous-processus tels que os.wait() et os.kill.

Je ne sais pas si cela correspond ou non à votre problème, mais un multiprocessing.Pool() peut être utile. Il gère automatiquement un pool de sous-processus et les réutilise pour les tâches futures. Il est surtout utile lorsqu'il n'y a qu'un échange de données limité entre les processus et que le travail est relativement homogène (tous les processus enfants effectuent le même type de travail).

+0

Mais le processus principal dure très longtemps – Alex

+0

Oui, c'est peut-être un moyen approprié. Chaque fois qu'un nouvel enfant est créé, l'ancien est détruit. Pas vraiment sympa, mais au moins je ne finirai pas avec des centaines de processus zombies ... – Alex

+0

CE problème devrait être vraiment résolu avec un PEP – Alex

0

Lorsqu'un processus se termine, il reste dans la table de processus jusqu'à ce que quelque chose lit son code de retour. En supposant que ce soit linux, vous pouvez en faire un démon et faire en sorte que le processus init le gère. Mais vous pouvez aussi appeler le os.waitpid. Voici un exemple de classe qui attend des pids en arrière-plan. C'est gentil car il empêche votre programme de sortir jusqu'à ce qu'il soit entièrement rangé. Vous pouvez l'étendre à faire des choses comme envoyer des signaux de tuer des processus enfants, les résultats d'exploitation forestière, etc. et

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