退出守护进程时出现问题
我正在编写一个守护程序,它会生成几个其他子进程。 在我运行 stop
脚本后,主进程在打算退出时继续运行,这真的让我很困惑。
import daemon, signal
from multiprocessing import Process, cpu_count, JoinableQueue
from http import httpserv
from worker import work
class Manager:
"""
This manager starts the http server processes and worker
processes, creates the input/output queues that keep the processes
work together nicely.
"""
def __init__(self):
self.NUMBER_OF_PROCESSES = cpu_count()
def start(self):
self.i_queue = JoinableQueue()
self.o_queue = JoinableQueue()
# Create worker processes
self.workers = [Process(target=work,
args=(self.i_queue, self.o_queue))
for i in range(self.NUMBER_OF_PROCESSES)]
for w in self.workers:
w.daemon = True
w.start()
# Create the http server process
self.http = Process(target=httpserv, args=(self.i_queue, self.o_queue))
self.http.daemon = True
self.http.start()
# Keep the current process from returning
self.running = True
while self.running:
time.sleep(1)
def stop(self):
print "quiting ..."
# Stop accepting new requests from users
os.kill(self.http.pid, signal.SIGINT)
# Waiting for all requests in output queue to be delivered
self.o_queue.join()
# Put sentinel None to input queue to signal worker processes
# to terminate
self.i_queue.put(None)
for w in self.workers:
w.join()
self.i_queue.join()
# Let main process return
self.running = False
import daemon
manager = Manager()
context = daemon.DaemonContext()
context.signal_map = {
signal.SIGHUP: lambda signum, frame: manager.stop(),
}
context.open()
manager.start()
stop
脚本只是一行代码 os.kill(pid, signal.SIGHUP)
,但之后子进程(工作进程和 http 服务器进程)就很好地结束了,但主要过程只是停留在那里,我不知道是什么阻止了它返回。
I am writing a daemon program that spawns several other children processes. After I run the stop
script, the main process keeps running when it's intended to quit, this really confused me.
import daemon, signal
from multiprocessing import Process, cpu_count, JoinableQueue
from http import httpserv
from worker import work
class Manager:
"""
This manager starts the http server processes and worker
processes, creates the input/output queues that keep the processes
work together nicely.
"""
def __init__(self):
self.NUMBER_OF_PROCESSES = cpu_count()
def start(self):
self.i_queue = JoinableQueue()
self.o_queue = JoinableQueue()
# Create worker processes
self.workers = [Process(target=work,
args=(self.i_queue, self.o_queue))
for i in range(self.NUMBER_OF_PROCESSES)]
for w in self.workers:
w.daemon = True
w.start()
# Create the http server process
self.http = Process(target=httpserv, args=(self.i_queue, self.o_queue))
self.http.daemon = True
self.http.start()
# Keep the current process from returning
self.running = True
while self.running:
time.sleep(1)
def stop(self):
print "quiting ..."
# Stop accepting new requests from users
os.kill(self.http.pid, signal.SIGINT)
# Waiting for all requests in output queue to be delivered
self.o_queue.join()
# Put sentinel None to input queue to signal worker processes
# to terminate
self.i_queue.put(None)
for w in self.workers:
w.join()
self.i_queue.join()
# Let main process return
self.running = False
import daemon
manager = Manager()
context = daemon.DaemonContext()
context.signal_map = {
signal.SIGHUP: lambda signum, frame: manager.stop(),
}
context.open()
manager.start()
The stop
script is just a one-liner os.kill(pid, signal.SIGHUP)
, but after that the children processes (worker processes and http server process) end nicely, but the main process just stays there, I don't know what keeps it from returning.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您创建了 http 服务器进程,但不
join()
它。 如果您不执行 os.kill() 来停止 http 服务器进程,而是向其发送停止处理哨兵(None
,就像发送到工人)然后执行self.http.join()
?更新:您还需要为每个工作人员将
None
标记发送到输入队列一次。 您可以尝试:注意,您需要两个循环的原因是,如果您将
None
放入执行join()
的同一循环中的队列中,则除
,因此加入w
之外的工作线程无法拾取任何内容w
将导致调用者阻塞。您没有显示工作人员或http服务器的代码,因此我假设这些在调用task_done等方面表现良好,并且每个工作人员一旦看到
None
就会退出,而无需get()
- 从输入队列中获取更多内容。另请注意,
JoinableQueue 至少存在一个未解决的、难以重现的问题 .task_done()
,这可能会困扰你。You create the http server process but don't
join()
it. What happens if, rather than doing anos.kill()
to stop the http server process, you send it a stop-processing sentinel (None
, like you send to the workers) and then do aself.http.join()
?Update: You also need to send the
None
sentinel to the input queue once for each worker. You could try:N.B. The reason you need two loops is that if you put the
None
into the queue in the same loop that does thejoin()
, thatNone
may be picked up by a worker other thanw
, so joining onw
will cause the caller to block.You don't show the code for workers or http server, so I assume these are well-behaved in terms of calling task_done etc. and that each worker will quit as soon as it sees a
None
, withoutget()
-ing any more things from the input queue.Also, note that there is at least one open, hard-to-reproduce issue with
JoinableQueue.task_done()
, which may be biting you.我尝试了一种不同的方法,这似乎有效(请注意,我取出了代码的守护进程部分,因为我没有安装该模块)。
一个警告是 signal.pause() 将对任何信号取消暂停,因此您可能需要相应地更改代码。
编辑:
以下内容对我来说效果很好:
您使用的是哪个版本的Python?
I tried a different approach, and this seems to work (note I took out the daemon portions of the code as I didn't have that module installed).
One warning, is that signal.pause() will unpause for any signal, so you may want to change your code accordingly.
EDIT:
The following works just fine for me:
What version of python are you using?