我有一个生产者使用PULL / PUSH向多个工人发送数据。在执行计算任务之前,所有工作人员都需要接收所有数据。
我尝试使用发送“go”的PUB / SUB套接字进行同步,但由于PUSH套接字是非阻塞的,因此在数据流结束之前收到go ...
发件人:
context = zmq.Context()
push_socket = self.context.socket(zmq.PUSH)
push_socket.bind("tcp://127.0.0.1:5557")
pull_socket = self.context.socket(zmq.PULL)
pull_socket.bind("tcp://127.0.0.1:5558")
for index, data in range(100):
push_socket.send_json({"data": data, "id": index})
pub_socket.send_json({"command": "map"})
接收者:
# recieve work
consumer_receiver = context.socket(zmq.PULL)
consumer_receiver.connect("tcp://127.0.0.1:5557")
# receive commands
consumer_command = context.socket(zmq.SUB)
consumer_command.subscribe("")
consumer_command.connect("tcp://127.0.0.1:5559")
poller = zmq.Poller()
poller.register(consumer_receiver, zmq.POLLIN)
poller.register(consumer_command, zmq.POLLIN)
while True:
events = dict(poller.poll(100))
if consumer_command in events:
received = consumer_command.recv_json()
command = received["command"]
print("received command : ", command)
if consumer_receiver in events:
received = consumer_receiver.recv_json()
print("received data", received)
接收器输出:
received data {'data': ['Hi'], 'id': 0}
received command : map
received data {'data': ['hi'], 'id': 1}
...
我想:
received data {'data': ['Hi'], 'id': 0}
received data {'data': ['hi'], 'id': 1}
...
received command : map
我试图为PUSH套接字设置1的HWM,但它不起作用。
如何在PUSH完成后向所有工作人员发送同步消息?
答案 0 :(得分:1)
您正在寻求实施障碍。
ZeroMQ是关于Actor模型编程的,其中一个特征是在发送和接收消息时没有隐含的显式渲染。也就是说,无论另一端是否已阅读该消息,都将返回发送。
所以这意味着必须在ZeroMQ的Actor模型之上合成障碍(一种类型的渲染)。
传达顺序流程
只是出于兴趣,您可能希望将Actor模型编程与Communicating Sequential Processes(在Rust,Erlang和(我认为?)中进行比较)Go正在做出一些东西卷土重来。在CSP发送/接收消息是一个集合。这有几个好处;
要使用CSP执行您想要的操作,您可以省略上面的步骤2和3。生产者会知道每个工人在发送给最后一个工人的时候都收到了数据,并且" go"可以立即发出。
就个人而言,我真的希望ZeroMQ可以选择成为CSP,而不是演员。然后它会很棒,而不仅仅是非常巨大。真正好的是它无论是tcp,ipc,inproc等都无关紧要。它们的行为都相同(显然速度变化)。
AFAIK Rust,Erlang和Go CSP频道不再是这个过程。 ZMQ可以是内部和/或内部处理和/或计算机间,这使得它非常适合于开发可能超出一台计算机的系统。需要将线程卸载到另一台计算机?更改连接字符串,不需要更改其他代码。很好。
答案 1 :(得分:0)
您正在为命令和数据使用单独的流 - 这将始终保证同步问题。在收件人方面,你将有两个流缓冲区 - 首先要处理大量数据,第二个只有命令和poll()将确保通知你两个都已准备好被读取。
我看到两种方法来解决这个问题:
1)保持简单:只使用一个流。最后发送的所有内容都将在最后收到。 TCP保证。如果你正在使用json,你可以添加它'输入':'命令'或者'输入':'数据'区分消息类型。
2)如果由于某种原因,您确实需要两个流(例如,您确实想要使用发布者/订阅者模式),接收方应在发送方发送其命令之前确认发送方接收最后一批数据。如果所有工作人员在使用该命令启动任何之前需要接收他们的数据,也可以选择此选项。