docstr: Blocks until all workers are terminated.
docstr_tok: ["Blocks","until","all","workers","are","terminated","."]
code: def join(self):
      """Blocks until all workers are terminated."""
  
      logger.debug("joining")
  
      # Slow joiner problem with zeromq means that not all workers are guaranteed to have gotten
      # the stop event. Therefore we will keep sending it until all workers are stopped to prevent
      # a deadlock.
      while any([w.poll() is None for w in self._workers]):
          self.stop()
          sleep(0.1)
  
      for w in self._workers:
          w.wait()
      self._ventilator_send.close()
      self._control_sender.close()
      self._results_receiver.close()
      self._context.destroy()
  
imports: import logging
  import pickle
  import sys
  import os
  from time import sleep, time
  from traceback import format_exc
  from threading import Thread
  from psutil import pid_exists
  import zmq
  from zmq import ZMQBaseError
  from petastorm.reader_impl.pickle_serializer import PickleSerializer
  from petastorm.workers_pool import EmptyResultError, VentilatedItemProcessedMessage
  from petastorm.workers_pool.exec_in_new_process import exec_in_new_process
label_desc: Use image node_id 8 for calling the ProcessPool obj's underlying member method code with example usage: obj.join() without return types