2008-11-26 14 views
43

से बाहर निकलने पर सबप्रोसेसेस मर चुके हैं क्या यह सुनिश्चित करने का कोई तरीका है कि सभी पाइथन प्रोग्राम के बाहर निकलने पर सभी निर्मित उपप्रोसेस मर गए हैं? Subprocess द्वारा मेरा मतलब है subprocess.Popen() के साथ बनाया गया है।पाइथन प्रोग्राम

यदि नहीं, तो क्या मुझे जारी करने वाली सभी हत्याओं पर फिर से शुरू करना चाहिए और फिर -9 को मारना चाहिए? कुछ क्लीनर?

+0

संबंधित: (http://stackoverflow.com/q/4789837/ [कैसे एक अजगर उपप्रक्रिया खोल के साथ शुरू = सच समाप्त करने के लिए] 4279) – jfs

+1

संबंधित: [पायथन: माता-पिता की मृत्यु होने पर बाल प्रक्रिया (एसएस) को कैसे मारना है?] (Http://stackoverflow.com/q/23434842/4279) – jfs

उत्तर

36

आप कर सकते हैं इसके लिए atexit का उपयोग करें, और जब आपका प्रोग्राम निकलता है तो चलाने के लिए किसी भी क्लीन अप कार्य को पंजीकृत करें।

atexit.register (समारोह [, * args [, ** kargs]])

अपने साफ़ करने की प्रक्रिया में, आप भी अपनी खुद की प्रतीक्षा लागू कर सकते हैं, और यह मारने जब एक अपने वांछित समय समाप्त होता है।

>>> import atexit 
>>> import sys 
>>> import time 
>>> 
>>> 
>>> 
>>> def cleanup(): 
...  timeout_sec = 5 
...  for p in all_processes: # list of your processes 
...   p_sec = 0 
...   for second in range(timeout_sec): 
...    if p.poll() == None: 
...     time.sleep(1) 
...     p_sec += 1 
...   if p_sec >= timeout_sec: 
...    p.kill() # supported from python 2.6 
...  print 'cleaned up!' 
... 
>>> 
>>> atexit.register(cleanup) 
>>> 
>>> sys.exit() 
cleaned up! 

नोट - पंजीकृत कार्यों अगर इस प्रक्रिया (मूल प्रक्रिया) मार दिया जाता है चलाने नहीं किया जाएगा।

निम्न विंडो विधि नहीं रह गया है अजगर> = 2.6

के लिए आवश्यक है यहाँ खिड़कियों में एक प्रक्रिया को मारने के लिए एक तरीका है। आपका popen वस्तु, एक पीआईडी ​​विशेषता है, इसलिए आप बस सफलता = win_kill (p.pid) (जरूरत pywin32 स्थापित) द्वारा यह कॉल कर सकते हैं:

def win_kill(pid): 
     '''kill a process by specified PID in windows''' 
     import win32api 
     import win32con 

     hProc = None 
     try: 
      hProc = win32api.OpenProcess(win32con.PROCESS_TERMINATE, 0, pid) 
      win32api.TerminateProcess(hProc, 0) 
     except Exception: 
      return False 
     finally: 
      if hProc != None: 
       hProc.Close() 

     return True 
+0

क्या आप विंडोज कोड में जो कुछ कर रहे हैं उसे समझा सकते हैं। –

+0

'win_kill' की आवश्यकता क्यों है, यह देखते हुए कि p.kill() मौजूद है? क्या यह प्री-2.6 पायथन उपयोगकर्ताओं के लिए है? –

+0

हां, मुझे उस समय विश्वास है, 2.5 अभी भी व्यापक उपयोग में था, और पी.किल() विंडोज़ में उपलब्ध नहीं था। – monkut

4

चुनाव()

चेक बच्चे प्रक्रिया को समाप्त कर लिया है। रिटर्नकोड विशेषता देता है।

2

वहाँ सब बनाया उपप्रक्रिया सुनिश्चित करने के लिए एक अजगर कार्यक्रम के निकास समय में मर चुके हैं कोई तरीका है? Subprocess द्वारा मेरा मतलब है subprocess.Popen() के साथ बनाया गया है।

आप कैप्सूलीकरण और परीक्षण का उल्लंघन हो सकता है कि सभी popen प्रक्रियाओं

subprocess._cleanup() 
print subprocess._active == [] 

करके समाप्त कर दिया है यदि नहीं, तो मैं जारी करने मारता की सब से अधिक पुनरावृति करना चाहिए और उसके बाद -9 को मारता है? कुछ क्लीनर?

आप यह सुनिश्चित नहीं कर सकते कि सभी उपप्रवाहों को बाहर जाने और हर जीवित व्यक्ति को मारने के बिना मर गए हैं। लेकिन अगर आपको यह समस्या है, तो शायद यह है क्योंकि आपके पास गहरी डिजाइन समस्या है।

14

subprocess.Popen.wait() यह सुनिश्चित करने का एकमात्र तरीका है कि वे मर चुके हैं। दरअसल, पॉज़िक्स ओएस की आवश्यकता है कि आप अपने बच्चों पर इंतजार करें। कई * निक्स की एक "ज़ोंबी" प्रक्रिया होगी: एक मृत बच्चा जिसके लिए माता-पिता इंतजार नहीं करते थे।

यदि बच्चा उचित रूप से अच्छी तरह लिखित है, तो यह समाप्त हो जाता है। अक्सर, बच्चे पीआईपीई से पढ़ते हैं। इनपुट बंद करना बच्चे को एक बड़ा संकेत है कि उसे दुकान बंद कर देना चाहिए और बाहर निकलना चाहिए।

अगर बच्चे की बग है और इसे समाप्त नहीं किया जाता है, तो आपको इसे मारना पड़ सकता है। आपको यह बग ठीक करना चाहिए।

यदि बच्चा "सेवा-हमेशा के लिए" लूप है, और इसे समाप्त करने के लिए डिज़ाइन नहीं किया गया है, तो आपको या तो इसे मारना चाहिए या कुछ इनपुट या संदेश प्रदान करना चाहिए जो इसे समाप्त करने के लिए मजबूर करेगा।


संपादित करें।

मानक ओएस में, आपके पास os.kill(PID, 9) है। किल -9 कठोर है, बीटीडब्ल्यू। यदि आप उन्हें SIGABRT (6?) या SIGTERM (15) के साथ मार सकते हैं जो अधिक विनम्र है।

विंडोज ओएस में, आपके पास os.kill काम नहीं करता है। विंडोज़ में एक प्रक्रिया को समाप्त करने के लिए इस ActiveState Recipe को देखें।

हमारे पास बाल प्रक्रियाएं हैं जो डब्लूएसजीआई सर्वर हैं। उन्हें समाप्त करने के लिए हम एक विशेष यूआरएल पर एक प्राप्त करते हैं; इससे बच्चे को साफ और बाहर निकलने का कारण बनता है।

28

* nix के पर, हो सकता है का उपयोग कर प्रक्रिया समूहों आप मदद कर सकते हैं - आप अपने उपप्रोसेसरों द्वारा उत्पन्न उपप्रोसेस को भी पकड़ सकते हैं। SIGTERM से (डिफ़ॉल्ट संकेत kill के लिए) SIGKILL को (kill -9 a.k.a):

if __name__ == "__main__": 
    os.setpgrp() # create new process group, become its leader 
    try: 
    # some code 
    finally: 
    os.killpg(0, signal.SIGKILL) # kill all processes in my group 

एक अन्य विचार संकेतों आगे भेजने के लिए है। kill -9 से पहले प्रक्रिया को स्पष्ट रूप से बाहर निकलने का मौका देने के लिए संकेतों के बीच थोड़ी देर प्रतीक्षा करें। अजगर कोड के लिए

1
+1

जबकि यह सैद्धांतिक रूप से प्रश्न का उत्तर दे सकता है, [यह बेहतर होगा] (http://meta.stackexchange.com/q/8259) यहां उत्तर के आवश्यक हिस्सों को शामिल करने के लिए, और संदर्भ के लिए लिंक प्रदान करें। – oers

2

मैं इस समस्या का एक छोटा सा बदलाव की जरूरत (subprocesses को साफ करने के लिए, लेकिन अजगर कार्यक्रम में ही बाहर निकले बिना), और के बाद से इसे यहाँ अन्य उत्तर में उल्लेख नहीं:

p=subprocess.Popen(your_command, preexec_fn=os.setsid) 
os.killpg(os.getpgid(p.pid), 15) 

setsid इस कार्यक्रम को एक नए सत्र में चलाएगा, इस प्रकार इसे और उसके बच्चों को एक नया प्रक्रिया समूह सौंपा जाएगा। इस पर os.killpg पर कॉल करने से इस प्रकार आपकी अपनी अजगर प्रक्रिया भी कम नहीं होगी।

+0

नहीं, आप नहीं कर सकते ... ... प्रक्रिया के सत्र को ही बदल देगा, अगर आप केवल बाद में बच्चों को मार रहे हैं तो यह नहीं है कि आप – berdario

+0

चाहते हैं, मैंने सवाल पढ़ लिया है, क्या आपने मेरा जवाब पढ़ा है? मैंने स्पष्ट रूप से लिखा है कि मुझे इस समस्या की एक छोटी भिन्नता की आवश्यकता है ... यदि आप "उपप्रजाय निकास बच्चों" के लिए Google हैं तो यह पहला परिणाम होगा जो आपको मिलेगा। वास्तव में, बाहर निकलने के बिना बच्चों को मारने में सक्षम होने से बाहर निकलने पर बस इसे करने से अधिक सामान्य समस्या होती है, इस प्रकार यह अन्य लोगों के लिए एक ही समस्या पर ठोकर खाएगा। – berdario

+0

स्टैकओवरफ्लो एफएक्स कहता है: 'क्या, विशेष रूप से सवाल पूछने वाला प्रश्न है? सुनिश्चित करें कि आपका उत्तर यह प्रदान करता है - या एक व्यवहार्य विकल्प। 'मैंने एक वैकल्पिक और उपयोगी उत्तर प्रदान किया है, इस बीच आपने पोस्ट किए गए दोनों उत्तरों को अभी घटा दिया है।यदि आप उन लोगों को परेशान करना बंद कर देंगे जो स्टैक ओवरफ्लो उपयोगकर्ताओं के लिए सहायक होने का प्रयास करते हैं, तो मुझे पूरा विश्वास है कि पूरा समुदाय इसका स्वागत करेगा। – berdario

4

चेतावनी: केवल लिनक्स! जब आपका माता-पिता मर जाता है तो आप अपने बच्चे को सिग्नल प्राप्त कर सकते हैं।

पहले पायथन-prctl == 1.5 स्थापित करें।0 तो के रूप में

subprocess.Popen(["sleep", "100"], preexec_fn=lambda: prctl.set_pdeathsig(signal.SIGKILL)) 

इस प्रकार अपने बच्चे की प्रक्रिया शुरू करने के लिए अपने माता पिता के कोड बदलने क्या यह कहते हैं:

  • लांच उपप्रक्रिया: 100
  • सो forking के बाद और उपप्रक्रिया, बच्चे के कार्यकारी से पहले मेरे माता-पिता को समाप्त होने पर "मुझे एक सिगिल भेजें" के लिए पंजीयक।
3

ओरिप का उत्तर सहायक है लेकिन यह नकारात्मक है कि यह आपकी प्रक्रिया को मारता है और आपके माता-पिता को एक त्रुटि कोड देता है।

class CleanChildProcesses: 
    def __enter__(self): 
    os.setpgrp() # create new process group, become its leader 
    def __exit__(self, type, value, traceback): 
    try: 
     os.killpg(0, signal.SIGINT) # kill all processes in my group 
    except KeyboardInterrupt: 
     # SIGINT is delievered to this process as well as the child processes. 
     # Ignore it so that the existing exception, if any, is returned. This 
     # leaves us with a clean exit code if there was no exception. 
     pass 

और फिर: मैं इस तरह कि बचा

with CleanChildProcesses(): 
    # Do your work here 

बेशक आप को छोड़कर/अंत में/कोशिश के साथ ऐसा कर सकते हैं, लेकिन आप अलग से असाधारण और गैर असाधारण मामलों को संभालने के लिए है।

+0

बिल्कुल मुझे जो चाहिए वह आपको धन्यवाद! – neok

2

मैं वास्तव में यह करने के लिए की जरूरत है, लेकिन यह रिमोट आदेश चल शामिल किया गया। हम सर्वर से कनेक्शन बंद करके प्रक्रियाओं को रोकने में सक्षम होना चाहते थे। इसके अलावा, अगर, उदाहरण के लिए, आप पाइथन प्रतिलिपि में चल रहे हैं, तो आप बाहर निकलने के लिए Ctrl-C का उपयोग करने में सक्षम होना चाहते हैं, तो आप अग्रभूमि के रूप में चलाने के लिए चुन सकते हैं।

import os, signal, time 

class CleanChildProcesses: 
    """ 
    with CleanChildProcesses(): 
     Do work here 
    """ 
    def __init__(self, time_to_die=5, foreground=False): 
     self.time_to_die = time_to_die # how long to give children to die before SIGKILL 
     self.foreground = foreground # If user wants to receive Ctrl-C 
     self.is_foreground = False 
     self.SIGNALS = (signal.SIGHUP, signal.SIGTERM, signal.SIGABRT, signal.SIGALRM, signal.SIGPIPE) 
     self.is_stopped = True # only call stop once (catch signal xor exiting 'with') 

    def _run_as_foreground(self): 
     if not self.foreground: 
      return False 
     try: 
      fd = os.open(os.ctermid(), os.O_RDWR) 
     except OSError: 
      # Happens if process not run from terminal (tty, pty) 
      return False 

     os.close(fd) 
     return True 

    def _signal_hdlr(self, sig, framte): 
     self.__exit__(None, None, None) 

    def start(self): 
     self.is_stopped = False 
     """ 
     When running out of remote shell, SIGHUP is only sent to the session 
     leader normally, the remote shell, so we need to make sure we are sent 
     SIGHUP. This also allows us not to kill ourselves with SIGKILL. 
     - A process group is called orphaned when the parent of every member is 
      either in the process group or outside the session. In particular, 
      the process group of the session leader is always orphaned. 
     - If termination of a process causes a process group to become orphaned, 
      and some member is stopped, then all are sent first SIGHUP and then 
      SIGCONT. 
     consider: prctl.set_pdeathsig(signal.SIGTERM) 
     """ 
     self.childpid = os.fork() # return 0 in the child branch, and the childpid in the parent branch 
     if self.childpid == 0: 
      try: 
       os.setpgrp() # create new process group, become its leader 
       os.kill(os.getpid(), signal.SIGSTOP) # child fork stops itself 
      finally: 
       os._exit(0) # shut down without going to __exit__ 

     os.waitpid(self.childpid, os.WUNTRACED) # wait until child stopped after it created the process group 
     os.setpgid(0, self.childpid) # join child's group 

     if self._run_as_foreground(): 
      hdlr = signal.signal(signal.SIGTTOU, signal.SIG_IGN) # ignore since would cause this process to stop 
      self.controlling_terminal = os.open(os.ctermid(), os.O_RDWR) 
      self.orig_fore_pg = os.tcgetpgrp(self.controlling_terminal) # sends SIGTTOU to this process 
      os.tcsetpgrp(self.controlling_terminal, self.childpid) 
      signal.signal(signal.SIGTTOU, hdlr) 
      self.is_foreground = True 

     self.exit_signals = dict((s, signal.signal(s, self._signal_hdlr)) 
           for s in self.SIGNALS)          

    def stop(self): 
     try: 
      for s in self.SIGNALS: 
       #don't get interrupted while cleaning everything up 
       signal.signal(s, signal.SIG_IGN) 

      self.is_stopped = True 

      if self.is_foreground: 
       os.tcsetpgrp(self.controlling_terminal, self.orig_fore_pg) 
       os.close(self.controlling_terminal) 
       self.is_foreground = False 

      try: 
       os.kill(self.childpid, signal.SIGCONT) 
      except OSError: 
       """ 
       can occur if process finished and one of: 
       - was reaped by another process 
       - if parent explicitly ignored SIGCHLD 
        signal.signal(signal.SIGCHLD, signal.SIG_IGN) 
       - parent has the SA_NOCLDWAIT flag set 
       """ 
       pass 

      os.setpgrp() # leave the child's process group so I won't get signals 
      try: 
       os.killpg(self.childpid, signal.SIGINT) 
       time.sleep(self.time_to_die) # let processes end gracefully 
       os.killpg(self.childpid, signal.SIGKILL) # In case process gets stuck while dying 
       os.waitpid(self.childpid, 0) # reap Zombie child process 
      except OSError as e: 
       pass 
     finally: 
      for s, hdlr in self.exit_signals.iteritems(): 
       signal.signal(s, hdlr) # reset default handlers 

    def __enter__(self): 
     if self.is_stopped: 
      self.start() 

    def __exit__(self, exit_type, value, traceback): 
     if not self.is_stopped: 
      self.stop() 

प्रारंभिक डिज़ाइन के लिए मैल्कम हैंडली के लिए धन्यवाद। लिनक्स पर python2.7 के साथ किया गया।

1

(स्थापित करने prctl के बिना) लिनक्स के लिए एक समाधान जानकारी प्राप्त करें:

def _set_pdeathsig(sig=signal.SIGTERM): 
    """help function to ensure once parent process exits, its childrent processes will automatically die 
    """ 
    def callable(): 
     libc = ctypes.CDLL("libc.so.6") 
     return libc.prctl(1, sig) 
    return callable 


subprocess.Popen(your_command, preexec_fn=_set_pdeathsig(signal.SIGTERM)) 
संबंधित मुद्दे