docs: def processpool_map(task, args, message, concurrency, batchsize=1, nargs=None):
      """
      See http://stackoverflow.com/a/16071616
      """
      njobs = get_njobs(nargs, args)
      show_progress = bool(message)
      batches = grouper(batchsize, tupleise(args))
      def batched_task(*batch):
          return [task(*job) for job in batch]
  
      if show_progress:
          message += ' (PP:{}w:{}b)'.format(concurrency, batchsize)
          pbar = setup_progressbar(message, njobs, simple_progress=True)
          pbar.start()
      
      q_in   = multiprocessing.Queue()  # Should I limit either queue size? Limiting in-queue
      q_out  = multiprocessing.Queue()  # increases time taken to send jobs, makes pbar less useful
  
      proc = [multiprocessing.Process(target=fun, args=(batched_task, q_in, q_out)) for _ in range(concurrency)]
      for p in proc:
          p.daemon = True
          p.start()
      sent = [q_in.put((i, x)) for (i, x) in enumerate(batches)]
      [q_in.put((None, None)) for _ in range(concurrency)]
      res = []
      completed_count = 0
      for _ in range(len(sent)):
          result = get_from_queue(q_out)
          res.append(result)
          completed_count += len(result[1])
          if show_progress:
              pbar.update(completed_count)
  
      [p.join() for p in proc]
      if show_progress:
          pbar.finish()
  
      return flatten_list([x for (i, x) in sorted(res)])