class_docstr: PS Synchronizer.
  
  Synchronizes gradient updates using a Parameter Server.
  
  For in-graph synchronization, this just aggregates gradients on a worker's CPU.
  
  For between-graph synchronization, this aggregates gradients on a pre-defined
  (defined in the Strategy) parameter server.
  
  To keep this gradient aggregation in sync, the chief gives each worker a token
  for each variable for the workers to mark when their variable update is complete.
docstr: Share the variable on the replica = `master_replica` (default to 0).
  
  Update inputs of consumers of the variable on replica > 0 to variable on replica=`master_replica`.
  
  Args:
      graph_item: the old graph item
      var_op_name: the name of the variable op of the variable to be shared
      master_replica: the index of master replica (default to 0)
docstr_tok: ["Share","the","variable","on","the","replica","=","`","master_replica","`","(","default","to","0",")",".","Update","inputs","of","consumers","of","the","variable","on","replica",">","0","to","variable","on","replica=","`","master_replica","`",".","Args",":","graph_item",":","the","old","graph","item","var_op_name",":","the","name","of","the","variable","op","of","the","variable","to","be","shared","master_replica",":","the","index","of","master","replica","(","default","to","0",")"]
code: def _share_variable(self, graph_item, var_op_name, master_replica=0):
      """
      Share the variable on the replica = `master_replica` (default to 0).
  
      Update inputs of consumers of the variable on replica > 0 to variable on replica=`master_replica`.
  
      Args:
          graph_item: the old graph item
          var_op_name: the name of the variable op of the variable to be shared
          master_replica: the index of master replica (default to 0)
      """
      for i in range(0, self.num_replicas):
          if i == master_replica:
              continue
          this_var_op_name = ops.prepend_name_scope(
              var_op_name, replica_prefix(i)
          )
          this_var_op = graph_item.graph.get_operation_by_name(
              this_var_op_name
          )
  
          # Get all read variable ops to this replica variable
          read_var_ops = get_read_var_ops(this_var_op)
  
          # Get all consumers of its VarhandleOp,
          # excluding ReadVariableOps and those not in its variable scope
          handle_consumers = set(get_consumers(this_var_op))
          handle_consumers.difference_update(set(read_var_ops))
          handle_consumers.difference_update(
              {
                  con
                  for con in handle_consumers
                  if con.name.startswith(this_var_op_name + "/")
              }
          )
          # We exclude the `update_op` when updating the consumers on the shared variables.
          # Because i) sharing variable indicates sharing its stateful ops correspondingly
          # (so it is ok to remove stateful ops in none-master replica but we just disconnect it)
          # ii) A variable cannot correspond to more than one update ops for now.
          handle_consumers.difference_update(
              set(graph_item.all_update_ops)
          )
  
          # update the consumers of all read variable ops to use the read variable ops of replica=master_replica
          for read_var_op in read_var_ops:
              new_read_var_op_name = ops.prepend_name_scope(
                  ops.strip_name_scope(
                      read_var_op.name, replica_prefix(i)
                  ),
                  replica_prefix(master_replica),
              )
              new_read_var_op = graph_item.graph.get_operation_by_name(
                  new_read_var_op_name
              )
              consumers = get_consumers(read_var_op)
              update_consumers(
                  consumers,
                  read_var_op.outputs[0],
                  new_read_var_op.outputs[0],
              )
              update_colocation_group(
                  consumers, read_var_op, new_read_var_op
              )
  
          # update the consumers of VarhandleOp to use the handle on replica=master_replica
          new_handle_op_name = ops.prepend_name_scope(
              ops.strip_name_scope(this_var_op_name, replica_prefix(i)),
              replica_prefix(master_replica),
          )
          new_handle_op = graph_item.graph.get_operation_by_name(
              new_handle_op_name
          )
          handle_consumers = list(handle_consumers)
          update_consumers(
              handle_consumers,
              this_var_op.outputs[0],
              new_handle_op.outputs[0],
          )
          update_colocation_group(
              handle_consumers, this_var_op, new_handle_op
          )
  
imports: from functools import partial
  from typing import List
  from tensorflow.python import ops
  from tensorflow.python.framework import device_spec, dtypes, constant_op
  from tensorflow.python.platform import tf_logging
  from tensorflow.python.ops import math_ops, data_flow_ops, gen_control_flow_ops, control_flow_ops, gen_math_ops, gen_array_ops
  from autodist.const import MAX_INT64, AUTODIST_PREFIX
  from autodist.kernel.common import utils, variable_utils
  from autodist.kernel.common.op_info import UPDATE_OP_VAR_POS
  from autodist.kernel.common.proxy_variable import ProxyVariable
  from autodist.kernel.common.utils import get_op_name, get_consumers, get_ancestors, traverse, update_consumers, update_control_consumers, replica_prefix, strip_replica_prefix, get_control_consumers, remove_from_control_consumers, get_index_from_tensor_name, update_colocation_group
  from autodist.kernel.common.variable_utils import get_read_var_ops
  from autodist.kernel.synchronization.synchronizer import Synchronizer
  from autodist.proto import synchronizers_pb2
label_desc: Use image node_id 3 for calling the PSSynchronizer obj's underlying member method code with example usage: obj._share_variable(graph_item, var_op_name, master_replica) without return types