'Kicks off threads which add data from the generator into the queue.
# Arguments
workers: number of worker threads
max_queue_size: queue size
(when full, threads could block on `put()`)'

def start(self, workers=1, max_queue_size=10):

    def data_generator_task():
        while (not self._stop_event.is_set()):
            try:
                if (self._use_multiprocessing or (self.queue.qsize() < max_queue_size)):
                    generator_output = next(self._generator)
                    self.queue.put(generator_output)
                else:
                    time.sleep(self.wait_time)
            except Exception:
                self._stop_event.set()
                raise
    try:
        if self._use_multiprocessing:
            self.queue = multiprocessing.Queue(maxsize=max_queue_size)
            self._stop_event = multiprocessing.Event()
        else:
            self.queue = queue.Queue()
            self._stop_event = threading.Event()
        for _ in range(workers):
            if self._use_multiprocessing:
                np.random.seed(self.random_seed)
                thread = multiprocessing.Process(target=data_generator_task)
                thread.daemon = True
                if (self.random_seed is not None):
                    self.random_seed += 1
            else:
                thread = threading.Thread(target=data_generator_task)
            self._threads.append(thread)
            thread.start()
    except:
        self.stop()
        raise
