了解ZMQ的HWM

时间:2017-03-22 10:23:15

标签: python zeromq pyzmq

我在理解ZeroMQ高水位线(HWM)排队的工作方式时遇到了一些麻烦。

我在下面附上了两个脚本,它们重现了以下内容。

  • 建立PUSH / PULL连接,将所有HWM队列设置为1。
  • 让拉拔器睡一段时间。
  • 从推送器发送2200条消息。
  • 当拉拔器唤醒时,接收2200条消息并打印出来。

我得到的结果是拉拔器能够成功接收(打印)所有消息。此外,推动器似乎几乎立即完成执行。根据{{​​3}}我所期望的是推拉器在拉出器唤醒之前没有完成执行,因为在第二次send(...)呼叫时由于HWM被阻止而被阻止。我还尝试在每个send(...)调用之间添加0.001秒的睡眠,结果相同。

所以,我的问题是:

  • 在达到HWM(大小1)后,为什么pusher在第二次调用send(...)时没有阻塞?
  • 消息和拉出器中存储的消息在哪里?
  • HWM大小与存储的消息数量之间是否存在直接关系?

脚本:

pusher.py

import zmq

context = zmq.Context()
push_socket = context.socket(zmq.PUSH)

push_socket.setsockopt(zmq.SNDHWM, 1)
push_socket.setsockopt(zmq.RCVHWM, 1)

push_socket.bind("tcp://127.0.0.1:5557")
print(push_socket.get_hwm()) # Prints 1
print('Sending all messages')

for i in range(2200):
    push_socket.send(str(i).encode('ascii'))

print('Finished execution...')

puller.py

import zmq
import time

context = zmq.Context()

pull_socket = context.socket(zmq.PULL)

pull_socket.setsockopt(zmq.RCVHWM, 1)
pull_socket.setsockopt(zmq.SNDHWM, 1)

pull_socket.connect("tcp://127.0.0.1:5557")
print(pull_socket.get_hwm()) # Prints 1

print('Connected, but not receiving yet... (Sleep 4s)')
time.sleep(4)
print('Receiving everything now!')

rec = ''

for i in range(2200):
    rec += '{} '.format(pull_socket.recv().decode('ascii'))

print(rec) # Prints `0 1 2 ... 2198 2199 `

为了重现我的测试用例,打开两个终端并在一个中启动第一个puller.py,然后在另一个中快速启动(4秒窗口)pusher.py。

1 个答案:

答案 0 :(得分:3)

这里至少涉及4个缓冲区:zmq发送缓冲区,OS写入tcp缓冲区,OS读取tcp缓冲区和zmq recv缓冲区。

zmq io线程将消息标记为"已发送"当它成功写入OS tcp写缓冲区时。这些消息现在被视为"在传输中#34;。

然后,网络堆栈负责尽可能多地将其转移到另一个进程中。匹配OS recv缓冲区, 最后,接收zmq io线程一次从该缓冲区读取大多数HWM消息到ZMQ recv队列。

默认情况下,OS缓冲区通常大约为10-100kb,并且这两个缓冲区都可以完全填满"在传输过程中#34; ZMQ之前的消息甚至注意到对方没有消费任何消息。出于性能原因,这些缓冲区是必需的 - 您无法摆脱它们。

你的问题的解决方案可能涉及req / rep套接字和一个明确的应用程序级别的ack,即指南中的懒惰盗版模式。