【问题标题】:How to catch SIGERM, SIGINT from a process running pyzmq?如何从运行 pyzmq 的进程中捕获 SIGERM、SIGINT?
【发布时间】:2015-08-06 16:22:32
【问题描述】:

我正在使用 PYZMQ,但似乎我无法再捕获 SIGTERM。如何优雅地处理 SIGTERM ?

下面是代码sn-p:

from time import sleep
from signal import signal, SIGTERM, SIGINT
from threading import Lock, Thread
try:
    import cPickle as pickle
except ImportError:
    import pickle
import zmq


zmq_poller = None

class server(Thread, object):
    def __init__(self, transport):
        self.context = zmq.Context()
        self.zmq_socket = self.context.socket(zmq.PULL)
        self.zmq_socket.setsockopt(zmq.RCVTIMEO, 2000)
        self.zmq_socket.bind(transport)
        self.keep_running = True
        Thread.__init__(self)

    def process_data(self, data):
        data = self.decode(data)

    def decode(self, data):
        return pickle.loads(data)

    def run(self):
        while self.keep_running:
            try:
                data = self.zmq_socket.recv()
                self.process_data(data)
            except zmq.error.Again:
                pass
            except zmq.error as e:
                print e

    def stop(self):
        self.keep_running = False

def handle_stop(signum=None, frame=None):
    if zmq_poller:
        zmq_poller.stop()

if __name__ == '__main__':
    signal(SIGTERM, handle_stop)
    signal(SIGINT, handle_stop)
    mc = server('ipc:///tmp/abc')
    zmq_poller = mc
    mc.setDaemon(True)
    mc.start()
    mc.join()
    sleep(100)

如我们所见,如果我向进程发送 SIGTERM, SIGINT,则不会调用 handle_stop 信号处理程序

【问题讨论】:

  • 将您想要完成的事情生成到子线程中,并为您想要处理的信号创建一个信号处理程序。 Python 只能处理到父线程的信号,因此这将允许您隔离子线程的行为。如果子线程使用锁等操作系统资源,则需要小心正确地终止子线程。
  • 首先这是 Thread 的错误实现。我认为你不应该在父母身上睡 100 秒。您需要唤醒父线程才能处理信号。我会避免使用守护进程,因为它们会导致不良或意外的行为。我会检查线程是否应该在 run() 函数中死掉,如果有的话,我会做一个小小的睡眠。
  • 我会将套接字设置为具有超时的阻塞,然后在每次超时结束时检查子线程是否应该在 run() 内终止。如果超时时间很短,您可以很好地结束程序。您将需要安排父线程以处理您的信号处理程序,因此您不能使用睡眠。你应该以某种频率在父母身上旋转。我不知道是否有可能在 join() 上捕获信号。
  • @Matt 睡眠 100 秒仅用于测试目的。在生产代码中,不会这样使用
  • 由于只有父线程可以捕获信号,并且由于您的父线程没有调度,所以它无法捕获任何信号。

标签: python signals zeromq pyzmq


【解决方案1】:

你的问题的原因是你的主线程在threading.Thread.joinExecution of Python signal handlers被阻塞:

Python 信号处理程序不会在低级 (C) 信号处理程序内执行。相反,低级信号处理程序设置一个标志,告诉虚拟机稍后执行相应的 Python 信号处理程序(例如在下一个字节码指令处)

纯粹用 C 语言实现的长时间运行的计算(例如对大量文本进行正则表达式匹配)可以在任意时间内不间断地运行,而不管接收到任何信号。计算完成时将调用 Python 信号处理程序。

在 3.3 之前,signal 模块绝对不会公开您自己解决此问题所需的工具。因此,如果您无法升级到 3.3,解决方案是等待可中断的内容,例如 ConditionEvent。子线程在退出之前通知事件,主线程在加入子线程之前等待事件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-09
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多