code: def start_threads(self, n_threads):
      
      if n_threads == len(self._threads):
        return self
      
      # Terminate all previous tasks with the existing
      # event object, then create a new one for the next
      # generation of threads. The old object will hang
      # around in memory until the threads actually terminate
      # after another iteration.
      self._terminate.set()
      self._terminate = threading.Event()
  
      threads = []
  
      for _ in range(n_threads):
        worker = threading.Thread(
          target=self._consume_queue, 
          args=(self._terminate,)
        )
        worker.daemon = True
        worker.start()
        threads.append(worker)
  
      self._threads = tuple(threads)
      return self
docs: Terminate existing threads and create a 
      new set if the thread number doesn't match
      the desired number.
  
      Required: 
        n_threads: (int) number of threads to spawn
  
      Returns: self