Python multithreaded ZeroMQ REQ-REP
Question: I am looking to implement a REQ-REP pattern with Python and ZeroMQ using
multithreading.

With Python, I can create a new thread when a new client connects to the
server. This thread will handle all communications with that particular
client, until the socket is closed:

    
    
    # Thread that will handle client's requests
    class ClientThread(threading.Thread):
        # Implementation...
        def __init__(self, socket):
            threading.Thread.__init__(self)
            self.socket = socket
        def run(self):
            while keep_alive:
                # Thread can receive from client
                data = self.socket.recv(1024)
                # Processing...
                # And send back a reply
                self.socket.send(reply)
    
    while True:
        # The server accepts an incoming connection
        conn, addr = sock.accept()
        # And creates a new thread to handle the client's requests
        newthread = ClientThread(conn)
        # Starting the thread
        newthread.start()
    

Is it possible to do the same[*] using ZeroMQ? I have seen some examples of
multithreading with ZeroMQ and Python, but in all of them a pool of threads is
created with a fixed number of threads at the beginning and it seems to be
more oriented to load balancing.

[*] Notice what I want is to keep the connection between a client and its
thread alive, as the thread is expecting multiple REQ messages from the client
and it will store information that must be kept between messages (i.e.: a
variable counter that increments its value on a new REQ message; so each
thread has its own variable and no other client should ever be able to access
that thread). New client = new thread.


Answer: ## Yes, ZeroMQ is a powerfull Can-Do toolbox

However, the major surprise will be, that ZeroMQ <_socket_ >-s are by far more
structured than their plain counterparts, you use in the sample.

## { aZmqContext -> aZmqSocket -> aBehavioralPrimitive }

ZeroMQ builds a remarkable, abstraction-rich framework, under a hood of a
"**singleton** " ZMQ-**`Context`** , which is (and shall remain) the only
thing used as "shared".

Threads shall not "share" any other "derived" objects, the less any their
state, as there is a strong distributed-responsibility framework architecture
implemented, both in the sake of clean-design and a high performance & low-
latency.

For all ZMQ-**`Socket`** -s one shall rather imagine a much smarter, layered
sub-structure, where one receives off-loaded worries about I/O-activities (
managed inside ZMQ-**`Context`** responsibility -- thus keep-alive issues,
timing issues and fair-queue buffering / select-polling issues **simply
cease** to be visible for you ... ), with one sort of a formal communication
pattern **behaviour** ( given by a chosen ZMQ-`Socket`-type archetype ).

## Finally

**ZeroMQ** and similarly **nanomsg** libraries are rather LEGO-alike projects,
that empower you, as an architect & designer, more, than one typically
realises at the very beginning.

![enter image description here](http://i.stack.imgur.com/7ZWEf.gif)

One thus can focus on distributed-system behaviour, as opposed to lose time
and energy on solving just-another-socket-messaging-[nightmare].

( Definitely **worth to have a look** into both books from Pieter Hintjens,
co-father of the ZeroMQ. There you find plenty Aha!-moments on this great
subject. )

... and as a cherry on a cake -- you get all of this as a Transport-agnostic,
universal environment, whether passing some messages on **`inproc://`** ,
other over **`ipc://`** and also in parallel listening / speaking over
**`tcp://`** layers.

**`EDIT#1`**`2014-08-19 17:00 [UTC+0000]`

Kindly check comments below and further review your -- both elementary and
advanced -- design-options for a <_trivial-failure-prone_ >-spin-off
processing, for a <_load-balanced_ >-REP-worker queueing, for a <_scale-able_
>-distributed processing and a <_faul-resilient_mode_>-REP-worker binary-start
shaded processing.

## No heap of mock-up SLOC(s), no single code-sample will do a One-Size-Fits-
All.

This is exponentially valid in designing distributed messaging systems.

Sorry to say that.

**Hurts, but true.**

    
    
    """REQ/REP modified with QUEUE/ROUTER/DEALER add-on ---------------------------
    
       Multithreaded Hello World server
    
       Author: Guillaume Aubert (gaubert) <guillaume(dot)aubert(at)gmail(dot)com>
    
    """
    import time
    import threading
    import zmq
    
    print "ZeroMQ version sanity-check: ", zmq.__version__
    
    def aWorker_asRoutine( aWorker_URL, aContext = None ):
        """Worker routine"""
        #Context to get inherited or create a new one trick------------------------------
        aContext = aContext or zmq.Context.instance()
    
        # Socket to talk to dispatcher --------------------------------------------------
        socket = aContext.socket( zmq.REP )
    
        socket.connect( aWorker_URL )
    
        while True:
    
            string  = socket.recv()
    
            print( "Received request: [ %s ]" % ( string ) )
    
            # do some 'work' -----------------------------------------------------------
            time.sleep(1)
    
            #send reply back to client, who asked --------------------------------------
            socket.send( b"World" )
    
    def main():
        """Server routine"""
    
        url_worker = "inproc://workers"
        url_client = "tcp://*:5555"
    
        # Prepare our context and sockets ------------------------------------------------
        aLocalhostCentralContext = zmq.Context.instance()
    
        # Socket to talk to clients ------------------------------------------------------
        clients = aLocalhostCentralContext.socket( zmq.ROUTER )
        clients.bind( url_client )
    
        # Socket to talk to workers ------------------------------------------------------
        workers = aLocalhostCentralContext.socket( zmq.DEALER )
        workers.bind( url_worker )
    
        # --------------------------------------------------------------------||||||||||||--
        # Launch pool of worker threads --------------< or spin-off by one in OnDemandMODE >
        for i in range(5):
            thread = threading.Thread( target = aWorker_asRoutine, args = ( url_worker, ) )
            thread.start()
    
        zmq.device( zmq.QUEUE, clients, workers )
    
        # ----------------------|||||||||||||||------------------------< a fair practice >--
        # We never get here but clean up anyhow
        clients.close()
        workers.close()
        aLocalhostCentralContext.term()
    
    if __name__ == "__main__":
        main()
    

