多处理和金字塔:如何确保子进程实际结束?

时间:2013-09-14 15:25:05

标签: python queue multiprocessing pyramid waitress

我正在尝试在我的Pyramid应用程序中拥有一个工作进程池,可以用来执行CPU密集型(或长时间运行的)后台任务,我不想让这些任务陷入困境。我现在所做的工作,但有一个问题:如果女服务员从终止退出(就像--reload一样),工人们仍然挥之不去,我不知道如何发出信号让他们停下来。

编辑:使用Gunicorn(或仅从某个文件运行它)时,这似乎不是问题。这可能是女服务员的错误吗?

Edit2 :好吧。或者Gunicorn只是处理这种情况,使它看起来更好。

import multiprocessing as mp
from queue import Empty as QueueEmptyError

class MyPool(object):

    def __init__(self, processes=10, queue=None):
        self.jobqueue = queue if queue is not None else mp.Queue()
        self.procs = []
        self.running = True
        for i in range(processes):
            worker = mp.Process(target=self._worker, daemon=True)
            self.procs.append(worker)
            worker.start()

    def __del__(self):
        self.stopall()

    def stopall(self):
        self.running = False
        for worker in self.procs:
            worker.join()

    def _worker(self):
        while self.running:
            try:
                self._dojob(self.jobqueue.get(True, 1))
            except QueueEmptyError:
                pass

    def _dojob(self, taskdata):
        print(str(taskdata) + ' is happening')

class PoolMaster(object):
    def __init__(self):
        self.pools = []
        self.aqueue = mp.Queue()
        self.apool = MyPool(6, self.aqueue)
        self.pools.append(self.apool)

    def __del__(self):
        for pool in self.pools:
            pool.stopall()

    def do_something(self):
        self.aqueue.put_nowait('Something')

PoolMaster在我的项目的main()函数中实例化一次,并通过将其添加到所有事件来公开所有视图。

我之前尝试的是在__del__发生时向队列中添加“毒丸”,但事实证明__del__似乎根本没有被调用。我不想使用多处理自己的池,因为它们似乎是为了运行一次设置的工作负载,而不是经常在队列上工作。那么,在实际应用程序退出后如何阻止它们运行?

2 个答案:

答案 0 :(得分:0)

您可以为Pipe中的每个工作人员使用MyPool(例如cancelPipe)。然后,您的工作人员会定期收听Pipe部分取消代码(例如True)。要在工作进程中使用管道,您可以执行以下操作:

connections = mp.Pipe()
self.cancelPipes.append(connections[0])
worker = mp.Process(target=self._worker, daemon=True, args=[connections[1]])

然后,当您想要取消所有人时,请执行以下操作:

for c in self.cancelPipes:
    c.send(True)

工人们会检查他们是否应该停下来:

gotSomething = cancelPipe.poll()
if gotSomething:
    cancel = cancelPipe.recv()
    if cancel:
        # Stop your worker

答案 1 :(得分:0)

好吧,我找到了一种方法来改变_worker功能:

def _worker(self):
    while True:
        try:
            self._dojob(self.jobqueue.get(True, 3))
        except QueueEmptyError:
            pass
        if os.getppid() == 1:
            print('Parent process died, stopping worker.')
            sys.exit(0)

当父进程死亡而没有结束守护进程_worker进程os.getppid()将在类UNIX系统上返回1而不是父进程ID。它每隔3秒停止等待队列中的新对象并检查它。

我觉得这不是正确的方法。