单线程的ZeroMQ进程间通信丢失消息

时间:2013-04-11 10:01:52

标签: python unit-testing zeromq pyzmq

我目前正在探索测试我的zeromq应用程序的可能性。我的印象是我可以在同一个帖子中有一个发布者/订阅者,让发布者发布并且订阅者订阅它而不会丢失消息。然而,当我让发布者发送一些消息时,没有一个消息传递给订阅者。

以下是我使用的代码:

import zmq

def main():
    ctx = zmq.Context.instance()
    sender = ctx.socket(zmq.PUB)
    sender.setsockopt(zmq.HWM, 1000)
    sender.bind('tcp://*:10001')

    rcvr = ctx.socket(zmq.SUB)
    rcvr.setsockopt(zmq.HWM, 1000)
    rcvr.connect('tcp://127.0.0.1:10001')
    rcvr.setsockopt(zmq.SUBSCRIBE, "")

    for i in range(100):
        sender.send('%i' % i)

    while True:
        try:
            print rcvr.recv(zmq.NOBLOCK)
        except zmq.ZMQError:
            break


if __name__ == '__main__':
    main()

运行时,我没有任何输出。

让我感到震惊的是,接收方在发送方发送之前已经连接,因此应该排队这些消息。或者这是一个明显错误的假设,我应该使用PUSH / PULL?

3 个答案:

答案 0 :(得分:2)

我认为这是ZeroMQ guide

中描述的慢速木匠问题
  

这种“缓慢的木匠”症状经常会让足够多的人受到影响,我们将详细解释它。

我认为主要问题是所有消息都是在订阅者套接字开始侦听之前发送的,并且消息会随之消失并被丢弃。在设置套接字和发送消息之间设置延迟是行不通的,因为在接收器开始监听之前已经发送了最后的消息。

正如您所建议的那样,推/拉套接字会在内存中排队作业。您可以在单个进程中在套接字之间发送作业,如

# pushpull.py
import zmq

def main():
    ctx = zmq.Context()
    sender = ctx.socket(zmq.PUSH)
    sender.bind('tcp://*:10001')

    rcvr = ctx.socket(zmq.PULL)
    rcvr.connect('tcp://127.0.0.1:10001')

    for i in range(100):
        sender.send_unicode('%i' % i)

    while True:
        msg = rcvr.recv()
        print(msg)

if __name__ == '__main__':
    main()

或者如果你想使用pub / sub套接字,我们需要在套接字设置和消息发送之间有两个进程和一个time.sleep(1)

首先启动接收器

# rcvr.py
import zmq

def main():
    ctx = zmq.Context()
    rcvr = ctx.socket(zmq.SUB)
    rcvr.connect('tcp://127.0.0.1:10001')
    rcvr.setsockopt_string(zmq.SUBSCRIBE, "")

    while True:
        msg = rcvr.recv()
        print(msg)

if __name__ == '__main__':
    main()

然后是发件人,

# sender.py
import zmq
import time

def main():
    ctx = zmq.Context()
    sender = ctx.socket(zmq.PUB)
    sender.bind('tcp://*:10001')

    time.sleep(1)
    for i in range(100):
        sender.send_unicode('%i' % i)

if __name__ == "__main__":
    main()

接收:

b'0'
b'1'
b'2'
b'3' ...

我目前在Python 3.3和pyzmq 13.1.0中使用了令人敬畏的WinPython发行版,因此zmq调用中的一些字符串处理与print函数略有不同。 希望它有所帮助。

答案 1 :(得分:1)

您应该将SUB套接字连接到端口10000而不是10001.目前SUB套接字正在等待发布者,PUB套接字正在等待订阅者。 0mq允许“客户端”在没有“服务器”存在的情况下连接的功能也意味着当您连接到端口10001并且设计时没有抛出错误。

答案 2 :(得分:0)

  

让我感到震惊的是接收者在发送者发送之前已经连接

实际上并非如此 - 接收方已启动连接过程,但这并不意味着该过程已完成。连接是异步的。

如果您实际上将其用于进程内通信,我建议使用inproc传输,这不是问题:

url = 'inproc://whatever'
sender.bind(url)
...
recvr.connect(url)