class_docstr: Base class for the remote client.
  
  For each training task, there is a global client in the cluster which
  submits jobs to the master node. Different `@parl.remote_class` objects
  connect to the same global client in a training task.
  
  Attributes:
      submit_job_socket (zmq.Context.socket): A socket which submits job to
                                              the master node.
      pyfiles (bytes): A serialized dictionary containing the code of python
                       files in local working directory.
      executable_path (str): File path of the executable python script.
      start_time (time): A timestamp to record the start time of the program.
class_docstr_tok: ["Base","class","for","the","remote","client",".","For","each","training","task",",","there","is","a","global","client","in","the","cluster","which","submits","jobs","to","the","master","node",".","Different","`","@","parl.remote_class","`","objects","connect","to","the","same","global","client","in","a","training","task",".","Attributes",":","submit_job_socket","(","zmq.Context.socket",")",":","A","socket","which","submits","job","to","the","master","node",".","pyfiles","(","bytes",")",":","A","serialized","dictionary","containing","the","code","of","python","files","in","local","working","directory",".","executable_path","(","str",")",":","File","path","of","the","executable","python","script",".","start_time","(","time",")",":","A","timestamp","to","record","the","start","time","of","the","program","."]
docstr: Check if this job is still alive before establishing connection with it.
  Return: instance_id (int): an unique isntance id. -1 if the job is not ready for connection.
docstr_tok: ["Check","if","this","job","is","still","alive","before","establishing","connection","with","it",".","Return",":","instance_id","(","int",")",":","an","unique","isntance","id",".","-1","if","the","job","is","not","ready","for","connection","."]
code: def _check_job(self, job_ping_address, max_memory, gpu):
      """
      Check if this job is still alive before establishing connection with it.
      Return: instance_id (int): an unique isntance id. -1 if the job is not ready for connection.
      """
      # job_ping_socket: sends ping signal to job
      job_ping_socket = self.ctx.socket(zmq.REQ)
      job_ping_socket.linger = 0
      job_ping_socket.setsockopt(zmq.RCVTIMEO, int(0.9 * 1000))
      job_ping_socket.connect("tcp://" + job_ping_address)
      instance_id = self._generate_instance_id()
      try:
          job_ping_socket.send_multipart(
              [
                  remote_constants.HEARTBEAT_TAG,
                  to_byte(self.job_heartbeat_server_addr),
                  to_byte(str(max_memory)),
                  to_byte(gpu),
                  to_byte(instance_id),
              ],
          )
          job_ping_socket.recv_multipart()
      except zmq.error.Again:
          logger.error(
              "[Client] connects to a finished job, will try again, job_ping_address:{}".format(
                  job_ping_address
              )
          )
          instance_id = -1
      finally:
          job_ping_socket.close(0)
      return instance_id
  
imports: import cloudpickle
  import datetime
  import os
  import socket
  import sys
  import threading
  import zmq
  import parl
  import time
  import glob
  import multiprocessing
  from parl.utils import to_str, to_byte, get_ip_address, logger, isnotebook
  from parl.remote.utils import get_subfiles_recursively
  from parl.remote import remote_constants
  from parl.remote.grpc_heartbeat import HeartbeatServerThread, HeartbeatServerProcess
  from parl.remote.utils import get_version
label_desc: Use image node_id 9 for calling the Client obj's underlying member method code with example usage: obj._check_job(job_ping_address, max_memory, gpu) and returns: instance_id