web-dev-qa-db-ja.com

zeromq:無限待機を防ぐ方法は?

ZMQを始めたばかりです。ワークフローが次のアプリを設計しています:

  1. 多くのクライアントの1つ(ランダムなPULLアドレスを持っている)5555のサーバーにリクエストをプッシュする
  2. サーバーはクライアントのプッシュを永遠に待っています。 1つが来ると、その特定の要求に対してワーカープロセスが生成されます。はい、ワーカープロセスは同時に存在できます。
  3. そのプロセスがタスクを完了すると、結果をクライアントにプッシュします。

Push/PULLアーキテクチャがこれに適していると思います。これを修正してください


しかし、これらのシナリオをどのように処理しますか?

  1. client_receiver.recv()は、サーバーが応答に失敗すると無限の時間待機します。
  2. クライアントはリクエストを送信できますが、すぐに失敗するため、ワーカープロセスはserver_sender.send()で永久にスタックしたままになります。

それでは、Push/PULLモデルでtimeoutのようなものを設定するにはどうすればよいですか?


[〜#〜] edit [〜#〜]:user938949の提案に感謝します。作業中の答えを受け取り、後世のために共有しています。

64
Jesvin Jose

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)が発生します。

72
minrk

これはクイックハックでしたuser938949の答えと http://taotetek.wordpress.com/2011/02/02/python-multiprocessing-with-zeromq / 。うまくいけば、あなたの答えを投稿してください、あなたの答えをお勧めします

信頼性に関する永続的なソリューションが必要な場合は、 http://zguide.zeromq.org/page:all#toc64 を参照してください

Zeromq(ベータATM)のバージョン3.0は、ZMQ_RCVTIMEOおよびZMQ_SNDTIMEOでtimeoutをサポートします。 http://api.zeromq.org/3-0:zmq-setsockopt

サーバ

Zmq.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"

クライアント

ポーラーオブジェクトは、多くの受信ソケットでリッスンできます(上記の「ZeroMQを使用したPythonマルチプロセッシング」を参照してください。work_receiverでのみリンクしました。ループ、クライアントは1000msの間隔でポーリングします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"
15
Jesvin Jose

ZMQ_NOBLOCKを使用すると送信はブロックされませんが、ソケットとコンテキストを閉じようとすると、このステップはプログラムの終了をブロックします。

理由は、ソケットがピアを待機し、発信メッセージがキューに入れられるようにするためです。ソケットをすぐに閉じて、発信メッセージをバッファからフラッシュするには、ZMQ_LINGERを使用して0に設定します。

8
Adobri

Pollerを作成するのではなく、1つのソケットのみを待機している場合は、次のようにできます。

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

work_receiver.RCVTIMEOを設定する代わりに、状況に応じてタイムアウトが変わる場合、これを使用できます。

0
Mathieu Longtin