停止包含阻塞循环的python线程

时间:2014-07-23 08:16:37

标签: python multithreading

我正在尝试为ZeroMQ设计面向对象的接口。

我不想在我的进程中使用zmq接收器,但我不希望它用它的循环来阻止进程。所以我试图在另一个线程中启动循环。

class BaseZmqReceiver(BaseZmqNode):
    __metaclass__ = ABCMeta

    def __init__(self, host, port, hwm, bind, on_receive_callback):
        super(BaseZmqReceiver, self).__init__(host=host, port=port, bind=bind, hwm=hwm)
        self.node.on_message_callback = on_receive_callback
        self.stream = ZMQStream(self.socket)
        self.stream.on_recv(self.on_message_received)
        ZmqLoopRunner().start()

    def on_message_received(self, message):
        return self.node.on_message_callback(message)

    def create_node(self):
        return ReceivingNode(None, None)

class ZmqLoopRunner(Thread):

    def __init__(self):
        super(ZmqLoopRunner, self).__init__()
        self.loop = IOLoop.instance()

    def run(self):
        self.loop.start()

    def stop(self):
        self.loop.stop()

但是我不知道如何正确地停止这个线程,因为loop.start()方法是阻塞的。 我怎么能这样做?

1 个答案:

答案 0 :(得分:1)

1)如果它是关于Tornado IOLoop(更新:它不是),正确的方法是在单个IOLoop内use the nonblocking integration

2)要手动停止IOLoop,请从IOLoop线程调用IOLoop.instance().stop()

IOLoop.instance().add_callback(IOLoop.instance().stop)

add_callback()确保在IOLoop事件线程中调用stop()方法,并且IOLoop被彻底停止。

在您的代码中,这将是:

class BaseZmqReceiver(BaseZmqNode):
    __metaclass__ = ABCMeta

    def __init__(self, host, port, hwm, bind, on_receive_callback):
        super(BaseZmqReceiver, self).__init__(
            host=host, port=port, bind=bind, hwm=hwm)
        # ...
        self.zmq_runner = ZmqLoopRunner()
        # this will start a new thread.
        self.zmq_runner.start()

    def stop(self):
        self.zmq_runner.stop()

class ZmqLoopRunner(Thread):
    # ...
    def stop(self):
        """ 
        Call this from any thread, add_callback() will make sure 
        it runs in IOLoop thread.
        """
        self.loop.add_callback(self.loop.stop)  # Note the absence of parentheses

3)如果你需要线程在程序关闭时退出,你可以make it daemon。更加错误,因为它不会干净地关闭IOLoop

class ZmqLoopRunner(Thread):
    def __init__(self):
        super(ZmqLoopRunner, self).__init__()
        self.daemon = True