📜  tqdm 中断后继续 - Python (1)

📅  最后修改于: 2023-12-03 15:05:37.253000             🧑  作者: Mango

继续 tqdm 进度条

tqdm 是一个Python进度条库,它可以轻松地为代码创建进度条,以提供用户友好的提示和可视化,以及代码的估计剩余时间和完成进度。然而,当程序中断并重新启动时,如何在进度条上继续,以避免从头开始?

1. 使用position参数

在创建tqdm实例时,可以使用position参数指定进度条的位置。该参数可以是整数值,表示该进程的唯一标识符。这使得您可以在同一位置重新启动单个进度条,而不会打乱整个输出。

from tqdm import tqdm
import time

# 创建进度条实例并指定位置为0
pbar = tqdm(total=100, position=0)

# 循环迭代,并在每次迭代时更新进度条
for i in range(100):
    # 模拟一些计算任务
    time.sleep(0.1)
    pbar.update(1)

# 中断程序,重新启动后仍然需要继续。
# 可以使用相同的位置来继续进度条。
# 注意:此时不应先设置total
pbar = tqdm(total=100, position=0)

# 减少迭代次数,以显示继续
for i in range(50):
    # 模拟一些计算任务
    time.sleep(0.1)
    pbar.update(1)

# 关闭进度条
pbar.close()
2. 使用initial参数

在某些情况下,您可能不希望指定进度条的位置,或者可能已经将tqdm实例作为参数传递给其他函数。在这种情况下,可以使用initial参数来设置进度条的起始值,在重新启动程序后,进度条将从指定的位置开始而不是从零开始。

from tqdm import tqdm
import time

# 创建进度条实例并使用初始值
pbar = tqdm(total=100, initial=50)

# 迭代计算以更新进度条
for i in range(50, 100):
    # 模拟一些计算任务
    time.sleep(0.1)

    # 更新进度条
    pbar.update(1)

# 中断程序,重新启动后继续从50开始。
pbar = tqdm(total=100, initial=50)

# 在这里增加一些迭代次数以确定进度条是否继续。
for i in range(20):
    # 模拟一些计算任务
    time.sleep(0.1)

    # 更新进度条
    pbar.update(1)

# 关闭进度条
pbar.close()
3. 使用pickle序列化

在某些情况下,如果您的程序中断了,并且您无法指定进度条的位置或初始值,您可以使用Python的pickle序列化机制保存tqdm实例的当前状态,这样您可以在重启程序时恢复进度,并无需手动调整进度条位置或初始值。

import pickle
from tqdm import tqdm
import time

class Wrapper:
    '''
    仿造tqdm封装类,实现pickle序列化和重写__enter__和__exit__方法来保证实例的正确启动和关闭
    '''
    def __init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        self.pbar = None
        self.file = None

    def __enter__(self):
        self.file = open(self.kwargs.get('filename', 'progress.pkl'), 'wb')
        return self

    def __exit__(self, *exc):
        self.pbar.close()
        pickle.dump(self.kwargs, self.file)
        self.file.close()

    def start(self):
        if self.file is not None and os.path.exists(self.file.name):
            self.file = open(self.file.name, 'rb')
            kwargs = pickle.load(self.file)
            initial = kwargs.get('initial', 0)
            total = kwargs.get('total', None)
            desc = kwargs.get('desc', '')
            unit = kwargs.get('unit', 'it')
            unit_scale = kwargs.get('unit_scale', False)
            position = kwargs.get('position', None)
            dynamic_ncols = kwargs.get('dynamic ncols', False)
            leave = kwargs.get('leave', False)
            bar_format = kwargs.get('bar_format', None)
            initial = self.pbar.n if position is None else position
            self.pbar = tqdm(initial=initial, total=total, desc=desc, unit=unit, unit_scale=unit_scale, position=position, dynamic_ncols=dynamic_ncols, leave=leave,bar_format=bar_format, **self.kwargs)
        else:
            self.pbar = tqdm(*self.args, **self.kwargs)

    def update(self, n=1):
        self.pbar.update(n)

# 在上下文管理器中使用包装器,这样实例将在退出上下文时自动保存并关闭。
with Wrapper(total=100, desc='Task Description', filename='progress.pkl') as wrapper:
    # 在开始进度条实例前加入重启检查
    wrapper.start()
    for i in range(wrapper.pbar.n, 100):
        # 模拟一些计算任务
        time.sleep(0.1)

        # 更新进度条
        wrapper.update(1)
结论

在这篇文章中,我们介绍了 tqdm 库中间如何中断和继续。在 Pandas 实现数据预处理和数据分析的时候,可以使用 tqdm 记录中间执行情况,避免程序在繁重的计算任务中陷入死循环而造成挂起,初学者可以通过本文来深入了解 tqdm 库的用法。