Python多处理-看门狗进程?

Python多处理-看门狗进程?,python,multiprocessing,Python,Multiprocessing,在典型的“发布/订阅”设置中,我有一组长时间运行的流程,其中包含用于通信的队列 我想做两件事,但我不知道如何同时完成这两件事: 增加/解雇工人。例如,如果我看到挂起队列的大小变得太大,我希望能够添加额外的使用者 我的流程的看门狗-如果我的任何生产商或消费者崩溃,我希望得到通知 我可以单独做(2): try: while True: for process in workers + consumers: if not process.is_alive

在典型的“发布/订阅”设置中,我有一组长时间运行的流程,其中包含用于通信的队列

我想做两件事,但我不知道如何同时完成这两件事:

  • 增加/解雇工人。例如,如果我看到挂起队列的大小变得太大,我希望能够添加额外的使用者
  • 我的流程的看门狗-如果我的任何生产商或消费者崩溃,我希望得到通知
  • 我可以单独做(2):

    try:
        while True:
            for process in workers + consumers:
                if not process.is_alive():
                    logger.critical("%-8s%s died!", process.pid, process.name)
            sleep(3)
    except KeyboardInterrupt:
        # Python propagates CTRL+C to all workers, no need to terminate them
        logger.warn('Received CTR+C, shutting down')
    
    上面的块阻止我执行(1)

    所以我决定将代码转移到它自己的流程中

    这不起作用,因为
    process.is\u alive()
    仅适用于父级检查其子级的状态。在本例中,我要检查的进程是兄弟进程,而不是子进程


    我对如何进行有点困惑。我的主进程如何在监视子进程的同时支持对子进程的更改?

    多进程。池实际上已经内置了一个看门狗。它运行一个线程,每0.1秒检查一次工人是否死亡。如果有,它会启动一个新的来取代它:

    def _handle_workers(pool):
        thread = threading.current_thread()
    
        # Keep maintaining workers until the cache gets drained, unless the pool
        # is terminated.
        while thread._state == RUN or (pool._cache and thread._state != TERMINATE):
            pool._maintain_pool()
            time.sleep(0.1)
        # send sentinel to stop workers
        pool._taskqueue.put(None)
        debug('worker handler exiting')
    
    def _maintain_pool(self):
        """Clean up any exited workers and start replacements for them.
        """
        if self._join_exited_workers():
            self._repopulate_pool()
    
    这主要用于实现
    maxtasksperchild
    关键字参数,在某些情况下实际上是有问题的。如果一个进程在<代码> map 或<代码>应用< /COD>命令运行时死亡,并且该进程处于处理与该调用相关联的任务的中间,它将永远无法完成。有关该行为的更多信息,请参阅

    也就是说,如果您只想知道某个进程已死亡,您可以创建一个线程(而不是进程)来监视池中所有进程的PID,如果列表中的PID发生变化,您就知道某个进程已崩溃:

    def monitor_pids(pool):
        pids = [p.pid for p in pool._pool]
        while True:
          new_pids = [p.pid for p in pool._pool]
          if new_pids != pids:
              print("A worker died")
              pids = new_pids
          time.sleep(3)
    
    编辑:


    如果您正在滚动自己的
    实现,您可以从
    多处理.Pool
    中获得提示,并在父进程的后台线程中运行监控代码。检查进程是否仍在运行的速度很快,因此后台线程占用GIL的时间应该可以忽略不计。考虑<代码>多重处理。进程< /代码>看门狗每隔0.1秒运行一次!每3秒钟运行一次不会引起任何问题。

    您不能直接这样做,至少不能以您可以称之为“有意义的可读代码”的方式。为了管理它,您将需要一个抽象级别,将作业分配给可以接收上/下扩展命令的工人。坦白地说,这是一件非常复杂的事情,有现成的系统可以做到这一点,看看芹菜吧。@Puciek我在其他项目中也用过芹菜。它服务于不同的用例(AFAIK)——启动异步作业。我从来没有听说过使用它来管理长期运行的生产者和消费者。你可以很好地使用它来启动长期运行的作业,包括消费者服务器-所有脚本最终都是平等创建的,请记住禁用超时。它还附带了您似乎正在寻找的自动缩放功能。@knite为什么不在父进程的后台线程中运行代码呢?它大部分时间都在睡觉,所以与GIL在一起的时间应该不会明显影响主要流程的性能。@dano这是一个有趣的想法!我一直非常专注于找出复杂的多处理位,以至于我没有考虑使用线程作为看门狗。我没有使用池,因为我的制作人没有做相同的工作。但是我会看看源代码,看看是否可以借用它的一些功能-看起来有点棘手,但是…@knite好吧,你仍然可以使用
    。并非
    多处理池中的每个进程都需要执行相同的工作。不过,要通过
    多处理.Pool
    获得所需的自动缩放功能是很困难的。