tqdm多进程显示数据处理进度的方法

使用python多进程处理数据时,往往需要显示处理进度。大家首选的第一赶脚是应用tqdm模块显示数据进度,But,数据显示竟然是重叠的…
其实,该模块是支持多行显示的,进过测试,小有发现。但事先声明一下,以下程序在pycharm中显示会乱行,在命令行窗口显示是正常的,原因嘛,,,我也不清楚。

import time
from multiprocessing import Pool, RLock, freeze_support
from tqdm import tqdm


def my_process(process_name):
	# tqdm中的position参数需要设定呦!!!
    pro_bar = tqdm(range(50), ncols=80, desc=f"Process—{process_name} pid:{str(os.getpid())}",
                   delay=0.01, position=process_name, ascii=False)
    for file in pro_bar :
        time.sleep(0.2)
    pro_bar.close()


if __name__ == '__main__':
	print(f'父进程 {os.getpid()}')
    freeze_support()
    pro_num = 3
    # 多行显示,需要设定tqdm中全局lock
    p = Pool(pro_num , initializer=tqdm.set_lock, initargs=(RLock(),))
    for idx in range(pro_num ):
        p.apply_async(image_process, kwds={"process_name": idx})
    
    p.close()
    p.join()

运行效果如下图所示:(注意呦,展示的是在pycharm中的terminal中进行的)
在这里插入图片描述
另外,多进程显示处理进度方法也可以是单独开一个进程显示进度,其他进程仅进行数据处理。具体实现以后补充…


另一种解决思路就是:数据预处理和进度显示为单独进程,数据处理为其他进程,它们之间通过队列进行信息和数据的交互。示例代码如下:

from multiprocessing import Process, Queue, Manager
from tqdm import tqdm
from random import random, choice, randint
import string
import time

def load_data(data_queue, status_queue, pro_num):
    """
        加载数据

        :param status_queue: 数据处理进程准备状态
        :param data_queue: 加载数据队列
        :param pro_num: 推理进程数量
        :return: None
    """

    # 等待推理器初始化完成
    print('推理器初始化中...')
    predictor_num = 0
    start_t = time.time()
    while predictor_num != pro_num:
        if not status_queue.empty():
            status_msg = status_queue.get()
            predictor_num += 1
            print(status_msg)
        else:
            time.sleep(0.05)
    end_t = time.time()
    print(f'推理器初始化完成,共耗时{(end_t - start_t):.2f}s')

    # 加载图像数据到image_queue中
    image_files = range(100)
    image_progress = tqdm(image_files)
    for _ in image_progress:
        # 等待图像队列数据被处理
        while data_queue.full():
            time.sleep(0.05)

        # 图像加载到队列中
        cur_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
        image_progress.set_description(f'{cur_time}: [PID {os.getpid()}]-load_data')
        time.sleep(0.1)
        data_queue.put({"file_name": f"{''.join([choice(string.ascii_letters) for _ in range(6)])}.bmp"})

    # 输入加载完成信号
    while not data_queue.empty():
        time.sleep(0.05)
    [data_queue.put('OK') for _ in range(pro_num)]


def process_data(gpu_id, data_queue, status_queue, share_results):
    """
        推理图像

        :param gpu_id: 推理显卡ID
        :param data_queue: 推理数据队列,推理数据来源
        :param status_queue: 推理器状态队列
        :param share_results: 处理结果
        :return: None
    """

    # 实例化推理器
    time.sleep(randint(1, 5))
    cur_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
    status_queue.put(f'{cur_time}: 推理器[PID-{os.getpid()}, GPU-{gpu_id}]初始化完成!')

    # 初始化变量
    result_buffer = {}

    # 循环推理
    while True:
        # 等待图像加载到队列中
        while data_queue.empty():
            time.sleep(0.05)

        # 从队里中取数据进行处理
        data = data_queue.get()
        if data == 'OK':
            # 最后将结果再写入共享变量中,减少中间访问时,变量切换造成的资源浪费
            if len(result_buffer):
                share_results.update(result_buffer)
                result_buffer.clear()
            break
        else:
            fn = data['file_name']
            # 图像推理
            time.sleep(0.5)
            # 保存推理详细信息
            result_buffer[fn] = {"scores": random()}


def multiprocess_data(gpu_ids, predictor_per_gpu):
    """
        多进程推理图像,适用于加速推理大量图像

        :param gpu_ids: 推理显卡ID
        :param predictor_per_gpu: 每个显卡上实例化推理器的个数
        :return: None
    """

    # 初始化变量
    gpu_ids = [gpu_id for gpu_id in gpu_ids for _ in range(predictor_per_gpu)]
    gpu_pro_num = len(gpu_ids)
    image_q = Queue(maxsize=gpu_pro_num * (gpu_pro_num + 2))
    status_q = Queue()
    inf_results = Manager().dict()

    # 定义推理进程并依次启动
    predict_processes = [Process(target=process_data, args=(id, image_q, status_q, inf_results)) for id in gpu_ids]
    predict_processes.insert(0, Process(target=load_data, args=(image_q, status_q, gpu_pro_num)))
    [predict_process.start() for predict_process in predict_processes]
    [predict_process.join() for predict_process in predict_processes]

    # 保存最终嘴里结果
    for key, val in inf_results.items():
        pass
    print('Inference is finished!')


if __name__ == '__main__':
    multiprocess_data([0, 1], 3)

在这里插入图片描述

若还有其他处理方法,欢迎留言~ 觉得写的不错的,可以收藏+关注哦

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyCharm是一种流行的Python集成开发环境(IDE),它在编写和调试Python代码时非常便捷。当使用tqdm库和多进程时,在PyCharm中显示tqdm进度条可以有几种方法。 第一种方法是使用tqdm库自带的`multiprocessing`功能。在使用多进程时,可以将tqdm封装在一个函数或类中,并使用`tqdm_multiprocessing`函数来启动多进程。这样,每个进程都会有自己独立的tqdm进度条,并且可以在PyCharm中显示。这是因为`tqdm_multiprocessing`函数会自动检测当前是否运行在PyCharm中,并选择正确的进度显示方式。 第二种方法是使用`tqdm.auto`函数。这个函数可以根据当前运行环境自动选择合适的进度显示方式。在PyCharm中,它会选择使用`tqdm`库自带的多进程进度显示功能。使用这种方法,只需要将`tqdm.auto`函数作为进程的包装器,即可在PyCharm中显示多进程tqdm进度条。 第三种方法是使用PyCharm自带的外部工具功能。在PyCharm的设置中,可以配置外部工具来执行Python脚本。我们可以将Python脚本中使用到的tqdm多进程部分单独写成一个脚本,并将其配置为外部工具。这样,在PyCharm中运行外部工具时,会弹出一个命令行窗口显示多进程tqdm进度条。 无论使用哪种方法,在PyCharm中显示tqdm多进程进度条都可以提供实时的进度显示,帮助我们更好地了解程序的运行情况。这对于处理大规模数据或复杂计算任务非常有用,可以提高开发效率和代码可读性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值