Wrapping Pyro4 name server
Question: I made a class to allow me to start and stop a pyro name server from a script
(i.e. not having to start multiple programs such as in the
[tutorial](http://pythonhosted.org/Pyro4/tutorials.html)). The class is as
follow:

    
    
    class NameServer(Pyro4.threadutil.Thread):
        def __init__(self, host, isDeamon, port=0, enableBroadcast=True, 
                     bchost=None, bcport=None, unixsocket=None, nathost=None, natport=None):
            super(NameServer,self).__init__()
            self.setDaemon(isDeamon)
            self.host=host
            self.started=Pyro4.threadutil.Event()
            self.unixsocket = unixsocket
    
            self.port = port
            self.enableBroadcast = enableBroadcast 
            self.bchost = bchost
            self.bcport = bcport
            self.nathost = nathost
            self.natport = natport       
    
    
            #This code is taken from Pyro4.naming.startNSloop
            self.ns_daemon = Pyro4.naming.NameServerDaemon(self.host, self.port, self.unixsocket, 
                                                     nathost=self.nathost, natport=self.natport)
            self.uri    = self.ns_daemon.uriFor(self.ns_daemon.nameserver)
            internalUri = self.ns_daemon.uriFor(self.ns_daemon.nameserver, nat=False)
            self.bcserver=None
            self.ns = self.ns_daemon.nameserver        
    
            if self.unixsocket:
                hostip = "Unix domain socket"
            else:
                hostip = self.ns_daemon.sock.getsockname()[0]
                if hostip.startswith("127."):
                    enableBroadcast=False
                if enableBroadcast:
                    # Make sure to pass the internal uri to the broadcast responder.
                    # It is almost always useless to let it return the external uri,
                    # because external systems won't be able to talk to this thing anyway.
                    bcserver=Pyro4.naming.BroadcastServer(internalUri, self.bchost, self.bcport)
                    bcserver.runInThread()
    
    
        def run(self):
            try:
                self.ns_daemon.requestLoop()
            finally:
                self.ns_daemon.close()
                if self.bcserver is not None:
                    self.bcserver.close()
    
    
        def startNS(self):
            self.start()
    
        def stopNS(self):
            self.ns_daemon.shutdown()
            if self.bcserver is not None:
                self.bcserver.shutdown()
    

Now, if I run the following script

    
    
    import socket
    import Pyro4
    from threading import Thread
    import time
    from multiprocessing import Process
    import sys
    from datetime import datetime
    
    HMAC_KEY = "1234567890"
    
    Pyro4.config.HMAC_KEY = HMAC_KEY         
    sys.excepthook = Pyro4.util.excepthook 
    
    
    [... definition of class NameServer given previously ...]
    
    
    
    class Dummy:
        x = {}    
    
    
        def getX(self):
            return self.x
    
    
    class Worker(Process):
    
        def run(self): 
    
            Pyro4.config.HMAC_KEY = HMAC_KEY         
            sys.excepthook = Pyro4.util.excepthook    
    
            for i in range(10):
                a = datetime.now() 
                with Pyro4.Proxy("PYRONAME:dummy") as obj:   
                    obj.getX()  
                print i, (datetime.now() - a).total_seconds()
    
    
    
    def main():
    
    
        nameserver = NameServer(socket.gethostbyname(socket.gethostname()), False)
        nameserver.startNS()
    
        daemon=Pyro4.Daemon(socket.gethostname(), port=7676)                 # make a Pyro daemon
    
        obj = Dummy()
    
        uri=daemon.register(obj)   # register the greeting object as a Pyro object
        nameserver.ns.register("dummy", uri)  # register the object with a name in the name server
    
        thread = Thread(target = daemon.requestLoop)
        thread.setDaemon(1)
        thread.start()
        time.sleep(1)
    
        worker = Worker()
    
        worker.start()  
    
    
    
    if __name__ == "__main__":
        main()
    

I get the following output:

    
    
    0 1.078
    1 1.05
    2 1.013
    3 1.037
    4 1.013
    5 1.087
    6 1.063
    7 1.1
    8 1.063
    9 1.05
    

However, if I run this code as two different programs without using my
NameServer class, I dont get these delays. For example, runing the first
script:

    
    
    import Pyro4
    import sys
    
    HMAC_KEY = "1234567890"
    
    Pyro4.config.HMAC_KEY = HMAC_KEY         
    sys.excepthook = Pyro4.util.excepthook 
    
    
    class Dummy:
        x = {}    
    
        def getX(self):
            return self.x
    
    
    def main():
    
        obj = Dummy()
        Pyro4.Daemon.serveSimple({obj: "dummy"}, ns = False)    
    
    
    if __name__ == "__main__":
        main()
    

and the second script

    
    
    import Pyro4
    from multiprocessing import Process
    import sys
    from datetime import datetime
    
    HMAC_KEY = "1234567890"
    
    Pyro4.config.HMAC_KEY = HMAC_KEY         
    sys.excepthook = Pyro4.util.excepthook 
    
    
    
    class Worker(Process):
    
        def run(self): 
    
            Pyro4.config.HMAC_KEY = HMAC_KEY         
            sys.excepthook = Pyro4.util.excepthook    
    
            for i in range(10):
                a = datetime.now() 
                with Pyro4.Proxy("[the URI given by Pyro when running script 1]") as obj:   
                    obj.getX()  
                print i, (datetime.now() - a).total_seconds()
    
    
    def main():
    
        worker = Worker()
        worker.start()  
    
    
    if __name__ == "__main__":
        main()
    

I get the following results

    
    
    0 0.053
    1 0.049
    2 0.051
    3 0.05
    4 0.013
    5 0.049
    6 0.051
    7 0.05
    8 0.013
    9 0.049
    

... what can be wrong with the first approach? I don't understand why I get
delays of 1 second at each Pyro call. Profiling it tells me that it is the
socket method connect that takes 1 second...


Answer: I do not know what exactly is wrong, but you can try my new
[PyroMP](https://pypi.python.org/pypi/PyroMP "PyroMP") package which has a
wrapper for a the Pyro4 NameServer as well as an easy way to create processes.
Your example will look like:

    
    
    from threading import Thread
    import time
    from datetime import datetime
    
    import Pyro4
    import PyroMP
    import PyroMP.log_server as log
    
    
    class Dummy(object):
    
        def __init__(self):
            self.x = {}
    
        def getX(self):
            return self.x
    
    
    class Worker(PyroMP.Service):
    
        def run(self):
            logger = self.get_logger()
            for i in range(10):
                a = datetime.now()
                with Pyro4.Proxy("PYRONAME:dummy") as obj:
                    obj.getX()
                logger.info("{}: {}".format(i, (datetime.now() - a).total_seconds()))
    
    
    def main():
        with PyroMP.NameServer(), log.LogServer():
            log.set_loglevel("INFO")
    
            daemon = Pyro4.Daemon()# make a Pyro daemon
    
            obj = Dummy()
    
            uri = daemon.register(obj)   # register the greeting object as a Pyro object
            ns = PyroMP.NameServer.locate()
            ns.register("dummy", uri)  # register the object with a name in the name server
    
            thread = Thread(target=daemon.requestLoop)
            thread.setDaemon(1)
            thread.start()
            time.sleep(1)
    
            with Worker() as worker:
                worker.run()
    
    if __name__ == "__main__":
        main()
    

The output is:

    
    
    2014-02-19 18:56:32,877 - LogServer.WORKER               - INFO     - 0: 0.0
    2014-02-19 18:56:32,892 - LogServer.WORKER               - INFO     - 1: 0.016
    2014-02-19 18:56:32,892 - LogServer.WORKER               - INFO     - 2: 0.0
    2014-02-19 18:56:32,894 - LogServer.WORKER               - INFO     - 3: 0.001
    2014-02-19 18:56:32,940 - LogServer.WORKER               - INFO     - 4: 0.031
    2014-02-19 18:56:32,956 - LogServer.WORKER               - INFO     - 5: 0.015
    2014-02-19 18:56:32,956 - LogServer.WORKER               - INFO     - 6: 0.0
    

