class_docstr: A thread-safe data structure used to respond to resource request,
     maintaining the available computation resources in each worker.
  
  Attributes:
      worker_hostname (dict): A dict to record worker hostname.
      worker_vacant_jobs (dict): Record which vacant jobs does each
                                 worker has.
      worker_used_jobs (dict): Record which used jobs does each
                                 worker has.
      master_ip (str): IP address of the master node.
class_docstr_tok: ["A","thread-safe","data","structure","used","to","respond","to","resource","request",",","maintaining","the","available","computation","resources","in","each","worker",".","Attributes",":","worker_hostname","(","dict",")",":","A","dict","to","record","worker","hostname",".","worker_vacant_jobs","(","dict",")",":","Record","which","vacant","jobs","does","each","worker","has",".","worker_used_jobs","(","dict",")",":","Record","which","used","jobs","does","each","worker","has",".","master_ip","(","str",")",":","IP","address","of","the","master","node","."]
code: def __init__(self, master_ip, devices=[remote_constants.CPU]):
      self.worker_hostname = {}
      self.worker_vacant_jobs = defaultdict(dict)
      self.worker_used_jobs = defaultdict(dict)
      self.lock = threading.Lock()
      self.master_ip = master_ip
      error_message = "invalid devices: {}".format(",".join(devices))
      assert (
          len(
              set(devices)
              - set([remote_constants.CPU, remote_constants.GPU])
          )
          == 0
      ), error_message
      self.devices = devices
      self.cpu_resource = CpuResource()
      self.gpu_resource = GpuResource()
  
imports: import threading
  import random
  from collections import defaultdict
  from collections import namedtuple
  from parl.utils import logger
  from parl.remote import remote_constants
  from parl.remote.cpu_resource import CpuResource
  from parl.remote.gpu_resource import GpuResource
  from parl.remote.message import AllocatedCpu
  from parl.remote.message import AllocatedGpu
label_desc: Use image node_id 1 to create a new WorkerManager object from inherited base classes: object with example: obj = WorkerManager(master_ip, devices)