Python3如何正常关闭多进程应用程序

时间:2019-07-08 10:21:36

标签: multiprocessing queue python-3.7

我正在尝试修复python3应用程序,其中创建了多个进程和线程,这些进程和线程由各种队列和管道控制。当有人尝试使用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}

我得到上面的印刷,即将结束。 但是即时消息仍然有很多我试图抓住的不同例外,但事实并非如此。

我正在寻找有关如何以及以何种顺序关闭多进程及其主要进程的文档。

我知道这是一个非常普遍的问题,但是它的应用范围非常大,因此,如果有任何问题或我可以测试的东西,我可以将其范围缩小。

致谢

1 个答案:

答案 0 :(得分:0)

因此,在进一步研究了这个问题之后,我发现在运行管道线程,队列线程和4个多进程的情况下。当使用ctrl-c终止应用程序时,这些进程中的#个可能最终挂起。管道和队列进程已关闭。

在多处理文档中有一个警告。

  

警告如果相关进程正在使用   管道或队列,然后管道或队列很容易损坏,并且   可能无法通过其他过程使用。同样,如果该过程具有   获得了锁或信号量等,然后终止它可能会   导致其他进程陷入僵局。

我认为这是正在发生的事情。 我还发现,即使我在多进程类中具有关闭机制,即使我知道 run,仍在运行的线程仍会被认为是活动的(读取 is_alive())。 ()方法已返回IE som内部被挂起。

现在解决。我的多进程用于设计视图而不是Deamon,因为我想控制它们的击落。但是我将它们更改为Deamon,因此无论如何它们都会被杀死。我首先补充说,在我的整个程序中,任何杀死信号都会引发和 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上运行。

致谢