由于连接不良,ZMQ对(用于信令)阻塞

时间:2015-02-11 20:01:24

标签: python zeromq blocking pyzmq

我有两个主题。一个是Worker Thread,另一个是Communication Thread

Worker Thread正在从串口读取数据,进行一些处理,然后将结果排入队列。

Communication Tthread正在从队列中读取结果并发送它。挑战在于连接是无线的,虽然通常存在,但它可能是不稳定的(在几分钟内进入和退出范围),如果我失去连接,我不想阻止Worker Thread

我为此选择的模式如下:

Worker Threadenqueue方法,可将消息添加到Queue,然后使用inproc://signalzmq.PAIR发送信号。

Communication Thread使用zmq.DEALER与服务器进行通信(zmq.ROUTER),但轮询inproc://signal对以便注册是否有新消息需要发送或不

以下是模式的简化示例:

import Queue
import zmq
import time
import threading
import simplejson


class ZmqPattern():
    def __init__(self):
        self.q_out = Queue.Queue()
        self.q_in = Queue.Queue()
        self.signal = None
        self.API_KEY = 'SOMETHINGCOMPLEX'
        self.zmq_comm_thr = None

    def start_zmq_signal(self):
        self.context = zmq.Context()

        # signal socket for waking the zmq thread to send messages to the relay
        self.signal = self.context.socket(zmq.PAIR)
        self.signal.bind("inproc://signal")

    def enqueue(self, msg):
        print("> pre-enqueue")
        self.q_out.put(msg)
        print("< post-enqueue")

        print(") send sig")
        self.signal.send(b"")
        print("( sig sent")

    def communication_thread(self, q_out):
        poll = zmq.Poller()

        self.endpoint_url = 'tcp://' + '127.0.0.1' + ':' + '9001'

        wake = self.context.socket(zmq.PAIR)
        wake.connect("inproc://signal")
        poll.register(wake, zmq.POLLIN)

        self.socket = self.context.socket(zmq.DEALER)
        self.socket.setsockopt(zmq.IDENTITY, self.API_KEY)
        self.socket.connect(self.endpoint_url)
        poll.register(self.socket, zmq.POLLIN)

        while True:
            sockets = dict(poll.poll())

            if self.socket in sockets:
                message = self.socket.recv()
                message = simplejson.loads(message)

                # Incomming messages which need to be handled on the worker thread
                self.q_in.put(message)

            if wake in sockets:
                wake.recv()
                while not q_out.empty():
                    print(">> Popping off Queue")
                    message = q_out.get()
                    print(">>> Popped off Queue")
                    message = simplejson.dumps(message)
                    print("<<< About to be sent")
                    self.socket.send(message)
                    print("<< Sent")

    def start(self):
        self.start_zmq_signal()
        # ZMQ Thread
        self.zmq_comm_thr = threading.Thread(target=self.communication_thread, args=([self.q_out]))
        self.zmq_comm_thr.daemon = True
        self.zmq_comm_thr.name = "ZMQ Thread"
        self.zmq_comm_thr.start()


if __name__ == '__main__':
    test = ZmqPattern()
    test.start()

    print '###############################################'
    print '############## Starting comms #################'
    print "###############################################"

    last_debug = time.time()
    test_msg = {}
    for c in xrange(1000):
        key = 'something{}'.format(c)
        val = 'important{}'.format(c)
        test_msg[key] = val

    while True:
        test.enqueue(test_msg)
        if time.time() - last_debug > 1:
            last_debug = time.time()
            print "Still alive..."

如果你运行这个,你会看到经销商阻塞,因为另一端没有路由器,不久之后,当Communication Thread未接收

时阻止对

我应该如何最好地将inproc zmq设置为不阻止Worker Thread

仅供参考,整个系统需要缓冲的最多是200k消息,每条消息大约256字节。

1 个答案:

答案 0 :(得分:1)

经销商插座对其存储的消息数量有限制,称为高水位线。在经销商套接字创建的正下方,尝试:

    self.socket = self.context.socket(zmq.DEALER)
    self.socket.setsockopt(zmq.SNDHWM, 200000)

并将这个数字设置为你敢于的数字;限制是你机器的记忆。

编辑:

在这个问题中对高水位的一些很好的讨论:

Majordomo broker: handling large number of connections