import os
import pickle
import json
import threading
import Pyro4.naming
[docs]def nic_name_to_host(nic_name):
""" helper function to translate the name of a network card into a valid host name"""
from netifaces import ifaddresses, AF_INET
host = ifaddresses(nic_name).setdefault(AF_INET, [{'addr': 'No IP addr'}] )[0]['addr']
return(host)
[docs]class NameServer(object):
"""
The nameserver serves as a phonebook-like lookup table for your workers. Unique names are created so the workers
can work in parallel and register their results without creating racing conditions. The implementation uses
`PYRO4 <https://pythonhosted.org/Pyro4/nameserver.html>`_ as a backend and this class is basically a wrapper.
"""
def __init__(self, run_id, working_directory=None, host=None, port=0, nic_name=None):
"""
Parameters
----------
run_id: str
unique run_id associated with the HPB run
working_directory: str
path to the working directory of the HPB run to store the nameservers credentials.
If None, no config file will be written.
host: str
the hostname to use for the nameserver
port: int
the port to be used. Default (=0) means a random port
nic_name: str
name of the network interface to use (only used if host is not given)
"""
self.run_id = run_id
self.host = host
self.nic_name = nic_name
self.port = port
self.dir = working_directory
self.conf_fn = None
self.pyro_ns = None
[docs] def start(self):
"""
starts a Pyro4 nameserver in a separate thread
Returns
-------
tuple (str, int):
the host name and the used port
"""
if self.host is None:
if self.nic_name is None:
self.host = 'localhost'
else:
self.host = nic_name_to_host(self.nic_name)
uri, self.pyro_ns, _ = Pyro4.naming.startNS(host=self.host, port=self.port)
self.host, self.port = self.pyro_ns.locationStr.split(':')
self.port = int(self.port)
thread = threading.Thread(target=self.pyro_ns.requestLoop, name='Pyro4 nameserver started by HpBandSter')
thread.start()
if not self.dir is None:
os.makedirs(self.dir, exist_ok=True)
self.conf_fn = os.path.join(self.dir, 'HPB_run_%s_pyro.pkl'%self.run_id)
with open(self.conf_fn, 'wb') as fh:
pickle.dump((self.host, self.port), fh)
return(self.host, self.port)
[docs] def shutdown(self):
"""
clean shutdown of the nameserver and the config file (if written)
"""
if not self.pyro_ns is None:
self.pyro_ns.shutdown()
self.pyro_ns = None
if not self.conf_fn is None:
os.remove(self.conf_fn)
self.conf_fn = None
def __del__(self):
self.shutdown()