显示多个进度条并立即更新它们,而无需打印多余的行

时间:2019-01-30 15:52:53

标签: python multiprocessing python-multiprocessing tqdm

Python版本:3.6

操作系统:Windows 10

我想使函数执行与多个参数并行。因此,我将multiprocessing对象Poolmap方法一起使用。由于每个函数调用都会持续几个小时,因此我想使用tqdm进度条来跟踪进度。

因此,我尝试了以下代码:

from datetime import date, timedelta
from multiprocessing.pool import Pool

from tqdm import tqdm


def some_func(date1):
    for i in range(1000000):
        pass


def load_data(date1, n_process):
    dLength = 100
    progressbar = tqdm(range(0, dLength), position=n_process)
    for i in range(dLength):
        some_func(date1)
        progressbar.update(i)

if __name__ == '__main__':

    d1 = date(2018, 5, 22)
    d2 = date(2018, 5, 26)

    delta = d2 - d1

    dates_range = []

    for i in range(delta.days + 1):
        date1 = d1 + timedelta(i)
        dates_range.append(date1)
    n_processes = 5

    with Pool(n_processes) as p:

        p.starmap(load_data, zip(dates_range, range(n_processes)))

问题是进度条开始重复并且不便于跟踪:

0%| | 0/101373 [00:00

0%| | 0/101373 [00:05

0%| | 1/101373 [00:09 <128:35:56,4.57s / it]   0%| | 0/217102 [00:01

0%| | 0/214016 [00:00

0%| | 3/101373 [00:11 <97:28:47,3.46s / it]

0%| | 0/214016 [00:01

0%| | 6/101373 [00:12 <72:00:37,2.56s / it]   0%| | 1/217102 [00:03 <81:07:30,1.35s / it]

0%| | 1/214016 [00:02 <66:16:01,1.11s / it]   0%| | 3/217102 [00:04 <66:47:19,1.11s / it]

我如何将文本转换为如下形式:

0%| | 0/101373 [00:00

0%| | 0/101373 [00:05

0%| | 0/217102 [00:00

0%| | 0/101373 [00:09 <128:35:56,4.57s / it]

0%| | 0/217102 [00:01

然后,在同一行中:

0%| | 1/101373 [00:00

0%| | 5/101373 [00:05

0%| | 20/217102 [00:00

0%| | 15/101373 [00:09 <128:35:56,4.57s / it]

0%| | 30/217102 [00:01

,依此类推...?

1 个答案:

答案 0 :(得分:0)

我也有同样的问题。我确定要显示每个进程的进度条以及一个指示整个进度的进度条,并保留一个额外的进程来维护所有进度条。 multiprocessing.Manager().Queue()用于进程之间的通信(以创建,更新和关闭进度条)。这是我的测试代码。

import multiprocessing
from time import sleep
from tqdm import tqdm
def maintain_pbar(queue, num_of_tasks):
    """
    {
        "id": taskid,
        "cmd": "create", "update", "terminate" or "finish"
        "data": int, parameters for cmd
        "message": string for updating the description of tqdm progress bar
    }
    """
    pbars = dict()
    overall_pbar = tqdm(total=num_of_tasks, ncols=80, desc="Total progress")
    while True:
        message = queue.get(True)
        if message["cmd"] == "create":
            pbars[str(message["id"])] = tqdm(total=message["data"],
                                             ncols=80,
                                             desc="Task #" + str(message["id"]) + message["message"])
        elif message["cmd"] == "update":
            pbars[str(message["id"])].update(message["data"])
        elif message["cmd"] == "terminate":
            pbars[str(message["id"])].close()
            overall_pbar.update()
        elif message["cmd"] == "finish":
            overall_pbar.close()
            break

def progresser(params):
    n = params[0]
    queue = params[1]
    interval = 0.01 / (n + 2)
    total = 5000
    queue.put({"id": n, "cmd": "create", "data": total, "message": ""})
    for _ in range(total):
        sleep(interval)
        queue.put({"id": n, "cmd":"update", "data": 1, "message":""})
    queue.put({"id": n, "cmd": "terminate", "data": 1, "message": ""})

if __name__ == '__main__':
    pool = multiprocessing.Pool(4)
    queue = multiprocessing.Manager().Queue()
    l = [(i, queue) for i in range(20)]
    pool.apply_async(maintain_pbar, (queue, len(l)))
    pool.map(progresser, l)
    queue.put({"cmd": "finish"})
    pool.close()
    pool.join()

希望这会有所帮助!