【问题标题】:Safe way to terminate a python subprocess?终止python子进程的安全方法?
【发布时间】:2020-08-30 18:44:28
【问题描述】:

我正在使用 python 的 multiprocessing 模块同时处理多个函数。每个衍生进程的函数都获取一些初始输入参数,以及一个Pipe 连接以将其结果发回。由于各种原因,我必须使用像这样的单个进程,即像 Pool.map_async()-methods 这样的工具不可用。

有时,我需要终止一个需要很长时间才能完成的进程。

根据the Process documentation

警告:如果在关联进程正在使用 管道或队列,则管道或队列可能会损坏,并且 可能无法被其他进程使用。同样,如果进程有 获得锁或信号量等,然后终止它很容易 导致其他进程死锁。

我不担心第一部分,因为每个进程都有自己的管道对象,但是我如何确定进程是否'获取了锁或信号量',和/或终止以对我的程序的其余部分安全的方式?

【问题讨论】:

    标签: python asynchronous concurrency multiprocessing concurrent-processing


    【解决方案1】:

    Q : "安全方式来终止 python 子进程?"

    好吧,如果有的话,你永远不会遇到这个。

    如果您的实际需求能够证明这样做的成本是合理的,那么最好的解决方法是向可靠处理、设计稳健、有弹性、自我修复系统的大师学习——比如 Margaret HAMILTON 女士(麻省理工学院)开创的在美国宇航局执行阿波罗登月计划,AGC(阿波罗导航计算机)设计得非常好,它可以在自己的死锁风险中幸存下来,防止鹰着陆器撞到月球表面。

    最佳灵感来自 ,如果使用强大且独立的多节点到多节点通信平面框架 ZeroMQ 或 nanomsg 设计安全和自我修复的自治组件,pythonistas 可以使用它。

    【讨论】:

      【解决方案2】:

      附带说明:检查您的子流程为何“完成时间过长”可能是值得的。

      至于警告,它与您何时“锁定”资源以供使用有关。例如:

      # function to withdraw from account 
      def withdraw(balance, lock):     
          for _ in range(10000): 
              lock.acquire() 
              balance.value = balance.value - 1
              lock.release() 
      

      来源:https://www.geeksforgeeks.org/synchronization-pooling-processes-python/

      如果您在子进程执行lock.acquire() 和执行lock.release() 之前终止子进程,您将遇到死锁情况。

      所以问题是,您是否在要终止的进程中使用任何 threading.Lock 或 threading.Semaphore 对象?

      我希望这有助于了解终止子进程/线程是否安全。

      编辑:顺便说一句,您还应该考虑使用 kill() 而不是 terminate()。

      【讨论】:

      • 谢谢。我没有在这个过程中明确地做任何线程的事情,但我依靠 pandas 进行计算,所以我担心这会在幕后做类似的事情。
      • 您的策略如何解决子流程“内部”失去控制的问题,以实际执行您的建议(当它本身已经陷入僵局时)?
      • AFAIR,o/s kill 将强制子进程结束,但它在 python 生态系统之外,因此管道和 python 队列实例不会从 main-即使在 o/s kill 碰巧清除了场景的 o/s 视图(不是蟒蛇的视图)之后,也让整个马戏团崩溃,对吗?
      • @ahura,如果你不在线程之间共享你的数据,pandas 将没有理由锁定任何东西。如果您希望我们更深入地研究,在 OP 中分享您的一些代码可能会有所帮助。
      • @user3666197,我不确定你的意思。我试图解释的是锁定/死锁是如何工作的,我没有提供任何策略。关于'kill'而不是'terminate':根据进程,它可以更巧妙地处理'SIGINT'。但同样,我需要更深入地了解应用程序本身。
      【解决方案3】:

      在 *nix 上,您可以尝试向进程发送 SIGINT 而不是终止/杀死它并捕获 KeyboardInterrupt 异常以进行清理:

      from multiprocessing import Process
      import os
      import time
      import signal
      
      def f():
          try:
              while True:
                  time.sleep(1)
          except KeyboardInterrupt:
              print('Do the emergency cleanup here')
      
      p = Process(target=f)
      p.start()
      os.kill(p.pid, signal.SIGINT)
      p.join()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-25
        • 2018-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-22
        相关资源
        最近更新 更多