class_docstr: Base class for a master node, the control center for our cluster, which provides connections to workers and clients.
  
  There is only one master node in each cluster, and it is responsible for
  receiving jobs from the clients and allocating computation resources to
  run the jobs.
  
  To start a master node, we use the following xparl command line api:
  
  .. code-block:: python
  
      xparl start --port localhost:1234
  
  At the same time, a local worker will be started and connect to the
  master node.
  
  Attributes:
      worker_manager (WorkerManager): A thread-safe data structure used to 
                                      respond to resource request, maintaining
                                      the available computation resources in
                                      each worker.
      client_socket (zmq.Context.socket): A socket that receives submitted
                                         job from the client, and later sends
                                         job_address back to the client.
      master_ip(str): The ip address of the master node.
      cpu_num(int): The number of available CPUs in the cluster.
      worker_num(int): The number of workers connected to this cluster.
      cluster_monitor(dict): A dict to record worker status and client status.
      client_hostname(dict): A dict to store hostname for each client address.
  
  Args:
      port: The ip port that the master node binds to.
class_docstr_tok: ["Base","class","for","a","master","node",",","the","control","center","for","our","cluster",",","which","provides","connections","to","workers","and","clients",".","There","is","only","one","master","node","in","each","cluster",",","and","it","is","responsible","for","receiving","jobs","from","the","clients","and","allocating","computation","resources","to","run","the","jobs",".","To","start","a","master","node",",","we","use","the","following","xparl","command","line","api",":","..","code-block",":",":","python","xparl","start","--","port","localhost:1234","At","the","same","time",",","a","local","worker","will","be","started","and","connect","to","the","master","node",".","Attributes",":","worker_manager","(","WorkerManager",")",":","A","thread-safe","data","structure","used","to","respond","to","resource","request",",","maintaining","the","available","computation","resources","in","each","worker",".","client_socket","(","zmq.Context.socket",")",":","A","socket","that","receives","submitted","job","from","the","client",",","and","later","sends","job_address","back","to","the","client",".","master_ip","(","str",")",":","The","ip","address","of","the","master","node",".","cpu_num","(","int",")",":","The","number","of","available","CPUs","in","the","cluster",".","worker_num","(","int",")",":","The","number","of","workers","connected","to","this","cluster",".","cluster_monitor","(","dict",")",":","A","dict","to","record","worker","status","and","client","status",".","client_hostname","(","dict",")",":","A","dict","to","store","hostname","for","each","client","address",".","Args",":","port",":","The","ip","port","that","the","master","node","binds","to","."]
code: def worker_num(self):
      return self.worker_manager.worker_num
  
imports: import os
  import pickle
  import threading
  import time
  import zmq
  from collections import deque, defaultdict
  import parl
  import sys
  from parl.utils import to_str, to_byte, logger, get_ip_address
  from parl.remote import remote_constants
  from parl.remote.worker_manager import WorkerManager
  from parl.remote.cluster_monitor import ClusterMonitor
  from parl.remote.grpc_heartbeat import HeartbeatClientThread
  import cloudpickle
  import time
  from parl.remote.utils import get_version
label_desc: Use image node_id 6 for calling the Master obj's underlying member method code with example usage: obj.worker_num() and returns: self