<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _setup_workers(self, initial_states=None):
 """ Create worker processes and queues. Distribute the work evenly across worker processes. Optionally send initial states defined in list `initial_states` to each worker process. """

        if initial_states is not None:
            require_listlike(initial_states)

        self.tasks_queues = []
        self.results_queue = mp.Queue()
        self.workers = []

        common_kwargs = dict(tokenizer=self.tokenizer,
                             stemmer=self.stemmer,
                             lemmata_dict=self.lemmata_dict,
                             pos_tagger=self.pos_tagger)

        if initial_states is not None:
            logger.info('setting up %d worker processes with initial states' % len(initial_states))

            for i_worker, w_state in enumerate(initial_states):
                task_q = mp.JoinableQueue()
                w = _PreprocWorker(i_worker, w_state.pop('docs'), self.language, task_q, self.results_queue,
                                   name='_PreprocWorker#%d' % i_worker, **common_kwargs)
                w.start()

                task_q.put(('set_state', w_state))

                self.workers.append(w)
                self.tasks_queues.append(task_q)

            [q.join() for q in self.tasks_queues]

        else:
            # distribute work evenly across the worker processes
            # we assume that the longer a document is, the longer the processing time for it is
            # hence we distribute the work evenly by document length
            logger.info('distributing work via greedy partitioning')

            docs_and_lengths = {dl: len(dt) for dl, dt in self.docs.items()}
            docs_per_worker = greedy_partitioning(docs_and_lengths, k=self.n_max_workers)

            logger.info('setting up %d worker processes' % len(docs_per_worker))

            for i_worker, doc_labels in enumerate(docs_per_worker):
                if not doc_labels: continue
                task_q = mp.JoinableQueue()
                w_docs = {dl: self.docs.get(dl) for dl in doc_labels}

                w = _PreprocWorker(i_worker, w_docs, self.language, task_q, self.results_queue,
                                   name='_PreprocWorker#%d' % i_worker, **common_kwargs)
                w.start()

                self.workers.append(w)
                self.tasks_queues.append(task_q)

        self.n_workers = len(self.workers)