Quantcast
Channel: Active questions tagged zeromq - Stack Overflow
Viewing all articles
Browse latest Browse all 193

Async request reply pattern in zeromq

$
0
0

I want to create a server that will handle a request / response scheme. The client of that server should be able to send multiple requests at one time (so REQ/REP does not fit). It should be like having a simple grpc server, a client is able send multiple requests and then wait on all responses.

I came into a few options. I saw that router-dealer can replace REP-REQ combo. This simple example I wrote does work. Here the client (dealer) sends 100 requests at the same time. (just as an example, in my real app I recv() one request and send() one response)

router.py

context = zmq.Context()socket = context.socket(zmq.ROUTER)port = 6000socket.bind(f"tcp://*:{port}")print(f"Listening on port :{port}")while True:    for i in range(100):        client_id = socket.recv()        msg = socket.recv()        print("Got ", msg)    socket.send(client_id, zmq.SNDMORE)    socket.send_string(f"Hello from router. Your message: {msg}")

dealer.py

port = 6000context = zmq.Context()socket = context.socket(zmq.DEALER)socket.connect(f"tcp://localhost:{port}")while True:    for i in range(100):        socket.send(f"hello from dealer1 {i}".encode())    time.sleep(1)    msg = socket.recv()    print("Got from server=", msg)

In a real app I need to know how to send / recv at the same time with the ROUTER socket.Say my app receives a message, send it to a background thread, then my app need to somehow send() the response. Not sure how to do that (maybe with poll() ?)

However, In the official guide https://zguide.zeromq.org/docs/chapter2/#sockets-and-patterns
I see this example:

import timeimport threadingimport zmqdef worker_routine(worker_url: str,                   context: zmq.Context = None):"""Worker routine"""    context = context or zmq.Context.instance()    # Socket to talk to dispatcher    socket = context.socket(zmq.REP)    socket.connect(worker_url)    while True:        string = socket.recv()        print(f"Received request: [ {string} ]")        # Do some 'work'        time.sleep(1)        # Send reply back to client        socket.send(b"World")def main():"""Server routine"""    url_worker = "inproc://workers"    url_client = "tcp://*:5555"    # Prepare our context and sockets    context = zmq.Context.instance()    # Socket to talk to clients    clients = context.socket(zmq.ROUTER)    clients.bind(url_client)    # Socket to talk to workers    workers = context.socket(zmq.DEALER)    workers.bind(url_worker)    # Launch pool of worker threads    for i in range(5):        thread = threading.Thread(target=worker_routine, args=(url_worker,))        thread.daemon = True        thread.start()    zmq.proxy(clients, workers)    # We never get here but clean up anyhow    clients.close()    workers.close()    context.term()if __name__ == "__main__":    main()
  1. Is the last implementation is more efficient than the other? i.e using one router socket to send / recv (probably with zmq.poll()), or using this pattern. Is there a cost involves with the inproc socket (serialization?), how does it works with zmq.proxy()?

  2. what is a better way of the two to implement client - server like I need?

  3. In the last implementation - can the server recv requests and send responses in parallel?

  4. Performance wise, how the last implementation compares with having pub/sub socket on each side - i.e server will use sub socket to get a request and pub socket to return a response. Client will also have the same pair of sockets. That will require two ports which is less convenient. But this way the server can send / recv in parallel (which I'm not sure is possible with the first implementation).


Viewing all articles
Browse latest Browse all 193

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>