我正在尝试在我的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__
似乎根本没有被调用。我不想使用多处理自己的池,因为它们似乎是为了运行一次设置的工作负载,而不是经常在队列上工作。那么,在实际应用程序退出后如何阻止它们运行?
答案 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秒停止等待队列中的新对象并检查它。
我觉得这不是正确的方法。