class_docstr: Base class for the job.
  
  After establishing connection with the remote object, the job will
  create a remote class instance locally and enter an infinite loop
  in a separate process, waiting for commands from the remote object.
class_docstr_tok: ["Base","class","for","the","job",".","After","establishing","connection","with","the","remote","object",",","the","job","will","create","a","remote","class","instance","locally","and","enter","an","infinite","loop","in","a","separate","process",",","waiting","for","commands","from","the","remote","object","."]
docstr: Args:
      worker_address(str): worker_address for sending job information(e.g, pid)
  
  Attributes:
      pid (int): Job process ID.
      max_memory (float): Maximum memory (MB) can be used by each remote instance.
      gpu (str): id list of GPUs can be used by each remote instance.
      job_id (str): Unique ID for the job. 
      instance_id (str): Unique instance ID to which the job connects.
docstr_tok: ["Args",":","worker_address","(","str",")",":","worker_address","for","sending","job","information","(","e.g",",","pid",")","Attributes",":","pid","(","int",")",":","Job","process","ID",".","max_memory","(","float",")",":","Maximum","memory","(","MB",")","can","be","used","by","each","remote","instance",".","gpu","(","str",")",":","id","list","of","GPUs","can","be","used","by","each","remote","instance",".","job_id","(","str",")",":","Unique","ID","for","the","job",".","instance_id","(","str",")",":","Unique","instance","ID","to","which","the","job","connects","."]
code: def __init__(self, worker_address, log_server_address):
      """
      Args:
          worker_address(str): worker_address for sending job information(e.g, pid)
  
      Attributes:
          pid (int): Job process ID.
          max_memory (float): Maximum memory (MB) can be used by each remote instance.
          gpu (str): id list of GPUs can be used by each remote instance.
          job_id (str): Unique ID for the job.
          instance_id (str): Unique instance ID to which the job connects.
      """
      self.max_memory = None
      self.gpu = ""
  
      self.job_address_receiver, job_address_sender = Pipe()
      self.job_id_receiver, job_id_sender = Pipe()
  
      self.worker_address = worker_address
      self.log_server_address = log_server_address
      self.job_ip = get_ip_address()
      self.pid = os.getpid()
      self.worker_pid = None
      """
          NOTE:
              In Windows, it will raise errors when creating threading.Lock before starting multiprocess.Process.
          """
      self.lock = threading.Lock()
      th = threading.Thread(target=self._create_sockets)
      th.setDaemon(True)
      th.start()
  
      process = psutil.Process(self.pid)
      self.init_memory = float(process.memory_info()[0]) / (1024**2)
  
      self.run(job_address_sender, job_id_sender)
  
      with self.lock:
          self.remove_job_socket.send_multipart(
              [remote_constants.KILLJOB_TAG, to_byte(self.job_address)]
          )
          try:
              _ = self.remove_job_socket.recv_multipart()
          except zmq.error.Again as e:
              pass
          os._exit(0)
  
imports: import os
  import compatible_trick
  import argparse
  import cloudpickle
  import pickle
  import psutil
  import re
  import sys
  import tempfile
  import shutil
  import threading
  import time
  import traceback
  import zmq
  import importlib
  import parl
  from multiprocessing import Process, Pipe
  from parl.utils import to_str, to_byte, get_ip_address, logger
  from parl.remote.communication import loads_argument, loads_return, dumps_argument, dumps_return
  from parl.remote import remote_constants
  from parl.utils.exceptions import SerializeError, DeserializeError
  from parl.remote.message import InitializedJob
  from parl.remote.utils import redirect_output_to_file
  from parl.remote.remote_class_serialization import load_remote_class
  from parl.remote.zmq_utils import create_server_socket, create_client_socket
  from parl.remote.grpc_heartbeat import HeartbeatServerThread, HeartbeatClientThread
label_desc: Use image node_id 1 to create a new Job object from inherited base classes: object with example: obj = Job(worker_address, log_server_address)