Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python zeromq:如何防止无限等待?_Python_Zeromq - Fatal编程技术网

Python zeromq:如何防止无限等待?

Python zeromq:如何防止无限等待?,python,zeromq,Python,Zeromq,我刚开始使用ZMQ。我正在设计一个应用程序,其工作流为: 许多客户端中的一个(具有随机拉地址)将请求推送到5555的服务器 服务器永远在等待客户端推送。当一个请求到达时,将为该特定请求生成一个工作进程。是的,辅助进程可以同时存在 当该进程完成其任务时,它将结果推送到客户端 我假设推/拉体系结构适合这种情况。请纠正我这一点 但我如何处理这些情况呢 当服务器无法响应时,client_receiver.recv()将等待无限长的时间 客户端可以发送请求,但之后会立即失败,因此工作进程将永远停留在服务

我刚开始使用ZMQ。我正在设计一个应用程序,其工作流为:

  • 许多客户端中的一个(具有随机拉地址)将请求推送到5555的服务器
  • 服务器永远在等待客户端推送。当一个请求到达时,将为该特定请求生成一个工作进程。是的,辅助进程可以同时存在
  • 当该进程完成其任务时,它将结果推送到客户端
  • 我假设推/拉体系结构适合这种情况。请纠正我这一点


    但我如何处理这些情况呢

  • 当服务器无法响应时,client_receiver.recv()将等待无限长的时间
  • 客户端可以发送请求,但之后会立即失败,因此工作进程将永远停留在服务器\ u sender.send()上
  • 那么,如何在推/拉模型中设置超时之类的设置呢



    编辑:感谢用户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将不会帮助您,因为超时后套接字仍无法关闭。这应添加到所选答案中。