मैं एक पायथन 3 एप्लिकेशन को ठीक करने की कोशिश कर रहा हूं जहां विभिन्न कतारों और पाइपों द्वारा नियंत्रित कई प्रोसेस और थ्रेड बनाए जाते हैं। जब कोई ctrl-c के साथ प्रोग्राम को तोड़ने का प्रयास करता है तो मैं नियंत्रित निकास का एक रूप बनाने का प्रयास कर रहा हूं। हालाँकि कोई फर्क नहीं पड़ता कि मैं क्या करता हूँ यह हमेशा अंत में लटका रहता है।

मैंने कीबोर्ड-इंटरप्ट अपवाद और सिग्नल कैच का उपयोग करने की कोशिश की है। नीचे दिया गया कोड मल्टी प्रोसेस कोड का हिस्सा है।

from multiprocessing import Process, Pipe, JoinableQueue as Queue, Event

class TaskExecutor(Process):
  def __init__(....)
    {inits}

  def signal_handler(self, sig, frame):
    print('TaskExecutor closing')
    self._in_p.close()
    sys.exit(1)

  def run
    signal.signal(signal.SIGINT, self.signal_handler)
    signal.signal(signal.SIGTERM, self.signal_handler)
    while True:
      # Get the Task Groupe name from the Task queue.
      try:
        ExecCmd = self._in_p.recv() # type: TaskExecCmd
      except Exceptions as e:
        self._in_p.close()
        return 
      if ExecCmd.Kill:
        self._log.info('{:30} : Kill Command received'.format(self.name))
        self._in_p.close()
        return
      else 
    {other code executing here}

मुझे उपरोक्त प्रिंट मिल रहा है कि यह बंद हो रहा है। लेकिन मुझे अभी भी कई अलग-अलग अपवाद मिल रहे हैं जिन्हें मैं पकड़ने की कोशिश करता हूं लेकिन ऐसा नहीं होगा।

मैं मल्टीप्रोसेस और इसकी मुख्य प्रक्रिया को कैसे और किस क्रम में बंद करना है, इस पर कुछ दस्तावेज ढूंढ रहा हूं।

मुझे पता है कि यह बहुत सामान्य प्रश्न है, हालांकि यह एक बहुत बड़ा अनुप्रयोग है, इसलिए यदि कोई प्रश्न या चीज है जिसका मैं परीक्षण कर सकता हूं तो मैं इसे कम कर सकता हूं।

सादर

0
Ephreal 8 जुलाई 2019, 13:21

1 उत्तर

सबसे बढ़िया उत्तर

तो इस मुद्दे की आगे जांच करने के बाद मैंने पाया कि ऐसी स्थिति में जहां मेरे पास पाइप थ्रेड, क्यू थ्रेड और 4 मल्टीप्रोसेस चल रहे थे। इन प्रक्रियाओं में से # ctrl-c के साथ एप्लिकेशन को समाप्त करते समय हैंग हो सकता है। पाइप और कतार प्रक्रिया जहां पहले ही बंद हो चुकी है।

मल्टीप्रोसेसिंग प्रलेखन में एक चेतावनी है।

चेतावनी यदि इस पद्धति का उपयोग तब किया जाता है जब संबंधित प्रक्रिया पाइप या कतार का उपयोग कर रही होती है तो पाइप या कतार दूषित होने के लिए उत्तरदायी होती है और अन्य प्रक्रिया द्वारा अनुपयोगी हो सकती है। इसी तरह, यदि प्रक्रिया ने लॉक या सेमाफोर इत्यादि प्राप्त कर लिया है तो इसे समाप्त करने से अन्य प्रक्रियाओं में डेडलॉक हो सकता है।

और मुझे लगता है कि यही हो रहा है। मैंने यह भी पाया कि भले ही मेरे बहु-प्रक्रिया वर्ग में शटडाउन तंत्र है, फिर भी चल रहे धागे को जीवित माना जाएगा (पढ़ना is_alive()) भले ही मुझे पता हो कि रन () मेथड ने IE को वापस कर दिया है कुछ इंटरनल हैंग हो रहा था।

अब समाधान की। मेरी मल्टीप्रोसेस एक डिज़ाइन व्यू के लिए थी, न कि डीमन क्योंकि मैं उनमें से शॉट डाउन को नियंत्रित करना चाहता था। हालाँकि मैंने उन्हें डीमॉन में बदल दिया ताकि वे हमेशा बिना किसी परवाह के मारे जा सकें। मैंने पहले जोड़ा कि कोई भी किल सिग्नल उठाएगा और मेरे पूरे कार्यक्रम में ProgramKilled अपवाद होगा।

def signal_handler(signum, frame):
  raise ProgramKilled('Task Executor killed')

फिर मैंने अपनी मल्टी प्रोसेस क्लास में अपना शट डाउन मैकेनिज्म बदल दिया

while True:
  # Get the Task Groupe name from the Task queue.
  try:
    # Reading from pipe
    ExecCmd = self._in_p.recv() # type: TaskExecCmd
  # If fatal error just close it all
  except BrokenPipe:
    break
  # This can occure close the pipe and break the loop
  except EOFError:
    self._in_p.close()
    break
  # Exception for when a kill signal is detected
  # Set the multiprocess as killed (just waiting for the kill command from main)
  except ProgramKilled:
    self._log.info('{:30} : Died'.format(self.name))
    self._KilledStatus = True
    continue
  # kill command from main recieved 
  # Shut down all we can. Ignore exceptions 
  if ExecCmd.Kill:
    self._log.info('{:30} : Kill Command received'.format(self.name))
    try:
      self._in_p.close()
      self._out_p.join()
    except Exception:
      pass
    self._log.info('{:30} : Kill Command executed'.format(self.name))
    break
  else if (not self._KilledStatus):
    {Execute code}

# When out of the loop set killed event
KilledEvent.set()

और मेरे मुख्य सूत्र में मैंने निम्नलिखित सफाई प्रक्रिया को जोड़ा है।

#loop though all my resources
for ThreadInterfaces in ResourceThreadDict.values():
  # test each process in each resource
  for ThreadIf in ThreadInterfaces:
    # Wait for its event to be set
    ThreadIf['KillEvent'].wait()
    # When event have been recevied see if its hanging 
    # We know at this point every thing have been closed and all data have been purged correctly so if its still alive terminate it. 
    if ThreadIf['Thread'].is_alive(): 
      try:
        psutil.Process(ThreadIf['Thread'].pid).terminate()
      except (psutil.NoSuchProcess, AttributeError):
        pass

बहुत सारे परीक्षण के बाद मुझे पता है कि कई प्रक्रियाओं के साथ समाप्ति और ऐप को नियंत्रित करना वाकई मुश्किल है क्योंकि आप बस यह नहीं जानते कि आपकी सभी प्रक्रियाओं को यह संकेत किस क्रम में प्राप्त होता है।

मैंने अपने अधिकांश डेटा को मारने के बाद किसी तरह से बचाने की कोशिश की है। कुछ लोग तर्क देंगे कि ऐप को मैन्युअल रूप से समाप्त करते समय मुझे उस डेटा की क्या आवश्यकता है। लेकिन इस मामले में यह ऐप बहुत सारी बाहरी स्क्रिप्ट और अन्य एप्लिकेशन चलाता है और उनमें से कोई भी एप्लिकेशन को लॉक कर सकता है और फिर आपको इसे मैन्युअल रूप से मारने की आवश्यकता होती है, लेकिन फिर भी जो पहले ही निष्पादित हो चुका है, उसके लिए जानकारी को बरकरार रखता है।

तो यह मेरे वर्तमान ज्ञान के साथ मेरी वर्तमान समस्या का समाधान है। जो हो रहा है उस पर किसी भी इनपुट या अधिक गहन ज्ञान का स्वागत है। कृपया ध्यान दें कि यह ऐप linux और windows दोनों पर चलता है।

सादर

0
Ephreal 12 जुलाई 2019, 08:49