我有3个进程,我们称它们为host
和worker1
和worker2
。我希望worker1
和worker2
能够通过PUB / SUB套接字直接相互通信(间歇插入host
,所以我有以下设置:
# host
socket = ctx.Socket(zmq.PUB)
socket.bind('ipc:///tmp/comms')
# worker1
socket = ctx.Socket(zmq.PUB)
socket.connect('ipc:///tmp/comms')
socket.send(b'worker1')
# worker2
socket = ctx.Socket(zmq.SUB)
socket.connect('ipc:///tmp/comms')
socket.setsockopt(zmq.SUBSCRIBE, b'worker1')
socket.recv()
到目前为止,此设置无效。 worker1
发送正常,但是worker2
似乎从未收到过该消息。但是,如果我现在将设置更改为此:
# host
socket = ctx.Socket(zmq.PUB)
socket.connect('ipc:///tmp/comms')
# worker1
socket = ctx.Socket(zmq.PUB)
socket.connect('ipc:///tmp/comms')
socket.connect(b'worker1')
# worker2
socket = ctx.Socket(zmq.SUB)
socket.bind('ipc:///tmp/comms')
socket.setsockopt(zmq.SUBSCRIBE, b'worker1')
socket.recv()
效果很好。但是,如果我也绑定了host
,它将再次停止工作。
这是为什么?如果我现在有workerN
也需要订阅worker1
,该怎么办?如何绑定所有进程?这些绑定/连接语义是什么? host
不是一个长期存在的过程,不是通过bind
做正确的事情,如果是这样,为什么worker2
在connect
时无法接收恩?
MWE:https://gist.github.com/ooblahman/f8f9724b9995b9646ebdb79d26afd68a
import zmq
import time
from multiprocessing import Process
addr = 'ipc:///tmp/test_zmq'
def worker1():
ctx = zmq.Context()
sock = ctx.socket(zmq.PUB)
sock.connect(addr)
while True:
sock.send(b'worker1')
print('worker1 sent')
time.sleep(1)
def worker2():
ctx = zmq.Context()
sock = ctx.socket(zmq.SUB)
sock.connect(addr) # Change this to bind
sock.setsockopt(zmq.SUBSCRIBE, b'worker1')
while True:
sock.recv()
print('worker2 heard')
def main():
ctx = zmq.Context()
sock = ctx.socket(zmq.PUB)
sock.bind(addr) # Change this to connect (or remove entirely)
p1 = Process(target=worker1)
p2 = Process(target=worker2)
p1.start()
p2.start()
p1.join()
if __name__ == '__main__':
main()
答案 0 :(得分:1)
Q :“
host
不是一个长期存在的过程,而是通过bind
ing来做正确的事情,...?” < / em>
好吧, 没有人能说出 。
没有任何证据支持此类声明(“ being 寿命长的过程” ),则对于任何这样扣除的假设(” ...而言,该值越小,如果是, 为什么为{{1 }}在连接时无法接收?“ )
我们 可以告诉 :
worker2
可以尝试使用其中任何一种方法,无论是worker2
,成功,但无论收到与否{ .bind() | .connect() }
,都不会得到(一种完美的零禅)。这取决于许多其他因素,distributed-computing系统中的因素更多:
POSACK
列表(使用TOPIC
方法的调用和调用顺序),.setsockopt( zmq.SUBSCRIBE, ... )
端代理曾经发送过任何实际上与活动订阅的主题匹配的消息,则PUB
-端进行传输的任何此类潜在可传递消息,并具有来自发送方的所有必要传输方式, .send()
实例到预期接收方Context()
实例的手中,最后通过Context()
方法在任何预期接收方的本地传输),在上述第一个示例中,以 .recv()
角色担任worker1
的人实际上一无所获。
Q :“这是为什么?”
要求PUB
建立到另一个PUB
的传输链接不是合法的ZeroMQ正式通信原型模式-这种对PUB
方法的调用,负责要求设置,应该检查是否返回错误,故事的其余部分就像观察两个人,.connect()
中PUB
和host
中{{1} },他们都试图向麦克风大喊大叫,但没有人听过扬声器,所以再也听不到其他人的话。
可行但不起作用吗?
Q :“如果我现在还需要订阅
PUB
的{{1}},该怎么办?如何绑定所有进程?” < / em>
除非我们愿意,否则我们不需要worker1
。
如果workerN
要订阅worker1
,则可能.bind()
,但workerN
却不知道是否出现了任何新的worker1
(可能想要.bind()
),对吗?因此,worker1
通常被允许用于workerN
设置(原则上实际上是.connect()
)的动态变化的.connect()
侧N元队列-具有{ {1}}端在一个已知的传输类上...是,可以有多个使用多个AccessPoint的AccessPoint,...是,多个传输类-所有这些都可以从一个类中使用与一个或多个远程SUB
代理通信的同一个1:N
代理-是不是很酷?)-因为M:N
-建立了一个已知的访问点 PUB
的动态队列-代理在将来的某个未知时间尝试PUB
。