我正在开展一个项目,我有一群工人。我没有使用内置的multiprocessing.Pool
,但创建了自己的进程池。
它的工作方式是我创建了两个multiprocessing.Queue
实例 - 一个用于向工作人员发送工作任务,另一个用于接收结果。
每个工作人员都坐在一个永久运行的循环中:
while True:
try:
request = self.request_queue.get(True, 5)
except Queue.Empty:
continue
else:
result = request.callable(*request.args, **request.kwargs)
self.results_queue.put((request, result))
还有一些错误处理代码,但我把它留给了酿酒。每个工作进程都将daemon
设置为1
。
我希望正确关闭主进程和所有子进程进程。到目前为止我的经历(做Ctrl + C):
sudo kill -9
)。sys.exit()
似乎没有任何影响。我正在寻找一种处理此问题的“最佳实践”方式。我还在某处读到,关闭与Queue
和Pipe
进行交互的进程可能会导致它们与其他进程发生死锁(由于信号量和内部使用的其他内容)。
我目前的做法如下: - 找到一种向每个进程发送内部信号的方法(使用单独的命令队列或类似命令队列)将终止其主循环。 - 为发送shutdown命令的主循环实现信号处理程序。子进程将有一个子处理程序,用于设置它们忽略信号。
这是正确的方法吗?
答案 0 :(得分:1)
您需要注意的是处理您想要关闭时队列中有消息的可能性,因此您需要一种方法让您的进程干净地排空其输入队列。假设您的主进程是能够识别出是时候关闭的进程,那么您可以这样做。
None
),它永远不会像普通消息。在sentinel之后,刷新并关闭每个工作进程的队列。在您的工作进程中使用类似于以下伪代码的代码:
while True: # Your main processing loop
msg = inqueue.dequeue() # A blocking wait
if msg is None:
break
do_something()
outqueue.flush()
outqueue.close()
如果有多个进程可能在inqueue
上发送消息,则需要更复杂的方法。从Python 3.2或更高版本的monitor
中的logging.handlers.QueueListener
方法的源代码中获取的此示例显示了一种可能性。
"""
Monitor the queue for records, and ask the handler
to deal with them.
This method runs on a separate, internal thread.
The thread will terminate if it sees a sentinel object in the queue.
"""
q = self.queue
has_task_done = hasattr(q, 'task_done')
# self._stop is a multiprocessing.Event object that has been set by the
# main process as part of the shutdown processing, before sending
# the sentinel
while not self._stop.isSet():
try:
record = self.dequeue(True)
if record is self._sentinel:
break
self.handle(record)
if has_task_done:
q.task_done()
except queue.Empty:
pass
# There might still be records in the queue.
while True:
try:
record = self.dequeue(False)
if record is self._sentinel:
break
self.handle(record)
if has_task_done:
q.task_done()
except queue.Empty:
break