class_docstr: The client monitor watches the cluster status.
  
  Attributes:
      status (dict): A dict to store workers status and clients status.
class_docstr_tok: ["The","client","monitor","watches","the","cluster","status",".","Attributes",":","status","(","dict",")",":","A","dict","to","store","workers","status","and","clients","status","."]
docstr: Return a message of current cluster status.
docstr_tok: ["Return","a","message","of","current","cluster","status","."]
code: def get_status_info(self):
      """Return a message of current cluster status."""
      self.lock.acquire()
      worker_num = len(self.status["workers"])
      clients_num = len(self.status["clients"])
      used_cpus = 0
      vacant_cpus = 0
      used_gpus = 0
      vacant_gpus = 0
      for worker in self.status["workers"].values():
          used_cpus += worker.get("used_cpus", 0)
          vacant_cpus += worker.get("vacant_cpus", 0)
          used_gpus += worker.get("used_gpus", 0)
          vacant_gpus += worker.get("vacant_gpus", 0)
      self.lock.release()
      status_info = "has {} used cpus, {} vacant cpus, {} used_gpus, {} vacant_gpus.".format(
          used_cpus, vacant_cpus, used_gpus, vacant_gpus
      )
      return status_info
  
file_path: PARL/parl/remote/cluster_monitor.py
imports: import cloudpickle
  import threading
  from collections import defaultdict, deque
  from parl.utils import to_str
label_desc: Use image node_id 8 for calling the ClusterMonitor obj's underlying member method code with example usage: obj.get_status_info() and returns: status_info