Python zeromq:如何防止无限等待?
我刚开始使用ZMQ。我正在设计一个应用程序,其工作流为:Python zeromq:如何防止无限等待?,python,zeromq,Python,Zeromq,我刚开始使用ZMQ。我正在设计一个应用程序,其工作流为: 许多客户端中的一个(具有随机拉地址)将请求推送到5555的服务器 服务器永远在等待客户端推送。当一个请求到达时,将为该特定请求生成一个工作进程。是的,辅助进程可以同时存在 当该进程完成其任务时,它将结果推送到客户端 我假设推/拉体系结构适合这种情况。请纠正我这一点 但我如何处理这些情况呢 当服务器无法响应时,client_receiver.recv()将等待无限长的时间 客户端可以发送请求,但之后会立即失败,因此工作进程将永远停留在服务
但我如何处理这些情况呢
编辑:感谢用户938949的建议,我得到了一个有效答案,我将与后代分享。如果您使用的是zeromq>=3.0,那么您可以设置RCVTIMEO套接字选项:
client_receiver.RCVTIMEO = 1000 # in milliseconds
但一般来说,您可以使用轮询器:
poller = zmq.Poller()
poller.register(client_receiver, zmq.POLLIN) # POLLIN for recv, POLLOUT for send
和poller.poll()
需要超时:
evts = poller.poll(1000) # wait *up to* one second for a message to arrive.
evts
如果没有可接收的内容,则该列表将为空
您可以使用zmq.POLLOUT
进行轮询,以检查发送是否成功
或者,要处理可能发生故障的对等机的情况,请执行以下操作:
worker.send(msg, zmq.NOBLOCK)
可能就足够了,它总是会立即返回-如果发送无法完成,则会引发一个ZMQError(zmq.EAGAIN)。这是我在参考用户938949的答案和之后进行的一次快速攻击。如果你做得更好,请发布你的答案,我将推荐你的答案 对于那些想要持久解决可靠性问题的人,请参阅 zeromq(beta ATM)的3.0版支持ZMQ_RCVTIMEO和ZMQ_SNDTIMEO中的超时 服务器 NOBLOCK确保当客户端不存在时,send()不会阻塞
import time
import zmq
context = zmq.Context()
ventilator_send = context.socket(zmq.PUSH)
ventilator_send.bind("tcp://127.0.0.1:5557")
i=0
while True:
i=i+1
time.sleep(0.5)
print ">>sending message ",i
try:
ventilator_send.send(repr(i),zmq.NOBLOCK)
print " succeed"
except:
print " failed"
客户
轮询器对象可以在多个接收套接字上侦听(请参阅上面链接的“Python Multiprocessing with ZeroMQ”。我只在work\u receiver上链接了它。在无限循环中,客户端以1000毫秒的间隔轮询。socks对象在没有收到消息的情况下返回空
import time
import zmq
context = zmq.Context()
work_receiver = context.socket(zmq.PULL)
work_receiver.connect("tcp://127.0.0.1:5557")
poller = zmq.Poller()
poller.register(work_receiver, zmq.POLLIN)
# Loop and accept messages from both channels, acting accordingly
while True:
socks = dict(poller.poll(1000))
if socks:
if socks.get(work_receiver) == zmq.POLLIN:
print "got message ",work_receiver.recv(zmq.NOBLOCK)
else:
print "error: message timeout"
如果使用ZMQ_NOBLOCK,发送不会被阻止,但如果尝试关闭套接字和上下文,此步骤将阻止程序退出
原因是套接字等待任何对等方,以确保传出消息排队。要立即关闭套接字并刷新缓冲区中的传出消息,请使用ZMQ_LINGER并将其设置为0。如果您只等待一个套接字,而不是创建
轮询器,则可以执行以下操作:
if work_receiver.poll(1000, zmq.POLLIN):
print "got message ",work_receiver.recv(zmq.NOBLOCK)
else:
print "error: message timeout"
如果超时时间根据情况而变化,您可以使用此选项,而不是设置work\u receiver.RCVTIMEO
我不是0mq专家,但在许多类似情况下,最好在启动时创建工作人员池,而不是创建响应消息的工作人员。也许我误解了您。好的观点。我是实际上,我们计划对工人进行预分叉。我刚刚意识到,使用0mq可能很琐碎。你能详细介绍一下zmq.NOBLOCK吗?嗨,我们需要重新注册一个套接字(在轮询器中)吗每次我们断开并重新连接它时?不,只有当你关闭套接字并打开一个新的套接字时,你才需要重新注册。正如@Adobri和@mknaf在下面所说:如果使用zmq.RCVTIMEO
,你还需要设置zmq.LINGER
,否则套接字即使超时也不会关闭。在Python中,它是socket.setsockopt(zmq.RCVTIMEO,1000)
socket.setsockopt(zmq.LINGER,0)
message=socket.recv()
这两行都在python中工作:results\u receiver.RCVTIMEO=1000
和results\u receiver.setsockopt(zmq.RCVTIMEO,1000)
Python是否有select
?Ruby的库有一个类似IO.select
。您可以:如果ZMQ.select([read\u socket],nil,nil,20);put read_socket.recv;else;put'timeout 20 secs';end
zmq.RCVTIMEO如果不使用zmq.LINGER将不会帮助您,因为超时后套接字仍无法关闭。这应添加到所选答案中。