web-dev-qa-db-fra.com

zeromq: comment éviter une attente infinie?

Je viens de commencer avec ZMQ. Je conçois une application dont le workflow est:

  1. l'un des nombreux clients (qui ont des adresses PULL aléatoires) Envoyer une demande à un serveur au 5555
  2. le serveur attend toujours les PUSH du client. Quand on arrive, un processus de travail est généré pour cette demande particulière. Oui, les processus de travail peuvent exister simultanément.
  3. Lorsque ce processus termine sa tâche, il POUSSE le résultat au client.

Je suppose que l'architecture Push/PULL est adaptée à cela. S'il vous plaît corrigez-moi à ce sujet.


Mais comment gérer ces scénarios?

  1. le client_receiver.recv () attendra un temps infini lorsque le serveur ne répond pas.
  2. le client peut envoyer une demande, mais elle échouera immédiatement après, donc un processus de travail restera bloqué à server_sender.send () pour toujours.

Alors, comment puis-je configurer quelque chose comme un timeout dans le modèle Push/PULL?


MODIFIER : Merci aux suggestions de user938949, j'ai reçu réponse de travail et je le partage pour la postérité.

64
Jesvin Jose

Si vous utilisez zeromq> = 3.0, vous pouvez définir l'option de socket RCVTIMEO:

client_receiver.RCVTIMEO = 1000 # in milliseconds

Mais en général, vous pouvez utiliser des sondeurs:

poller = zmq.Poller()
poller.register(client_receiver, zmq.POLLIN) # POLLIN for recv, POLLOUT for send

Et poller.poll() prend un timeout:

evts = poller.poll(1000) # wait *up to* one second for a message to arrive.

evts sera une liste vide s'il n'y a rien à recevoir.

Vous pouvez interroger avec zmq.POLLOUT, Pour vérifier si un envoi réussira.

Ou, pour gérer le cas d'un homologue qui aurait pu échouer, a:

worker.send(msg, zmq.NOBLOCK)

peut suffire, qui reviendra toujours immédiatement - en lançant une ZMQError (zmq.EAGAIN) si l'envoi ne peut pas se terminer.

72
minrk

Ce fut un hack rapide que j'ai fait après avoir référé la réponse de user938949 et http://taotetek.wordpress.com/2011/02/02/02/python-multiprocessing-with-zeromq / . Si vous faites mieux, veuillez poster votre réponse, Je recommanderai votre réponse .

Pour ceux qui souhaitent des solutions durables sur la fiabilité, reportez-vous http://zguide.zeromq.org/page:all#toc64

La version 3.0 de zeromq (beta ATM) prend en charge timeout dans ZMQ_RCVTIMEO et ZMQ_SNDTIMEO. http://api.zeromq.org/3-0:zmq-setsockopt

Serveur

Le zmq.NOBLOCK garantit que lorsqu'un client n'existe pas, send () ne se bloque pas.

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"

Client

L'objet poller peut écouter sur de nombreuses sockets de réception (voir le "Multiprocessing Python avec ZeroMQ" lié ci-dessus. Je l'ai lié uniquement sur work_receiver . Dans l'infini , le client interroge avec un intervalle de 1000 ms. L'objet socks retourne vide si aucun message n'a été reçu pendant cette période.

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"
15
Jesvin Jose

L'envoi ne bloquera pas si vous utilisez ZMQ_NOBLOCK, mais si vous essayez de fermer le socket et le contexte, cette étape empêcherait le programme de quitter.

La raison en est que le socket attend tout homologue afin que les messages sortants soient mis en file d'attente. Pour fermer immédiatement le socket et vider les messages sortants du tampon, utilisez ZMQ_LINGER et réglez-le sur 0.

8
Adobri

Si vous n'attendez qu'une seule socket, plutôt que de créer un Poller, vous pouvez le faire:

if work_receiver.poll(1000, zmq.POLLIN):
    print "got message ",work_receiver.recv(zmq.NOBLOCK)
else:
    print "error: message timeout"

Vous pouvez l'utiliser si votre délai d'attente change en fonction de la situation, au lieu de définir work_receiver.RCVTIMEO.

0
Mathieu Longtin