See http://stackoverflow.com/a/16071616

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)])