如何优化tqdm.set_postfix_str避免其拖慢程序运行速度?
问题描述
使用tqdm进度条工具追踪迭代过程的实时计算指标时,调用set_postfix_str方法更新进度条后缀会导致程序运行速度大幅下降,测试代码如下:
from tqdm import tqdm import time N = 10000 pbar = tqdm(range(N), total=N, desc="N") start = time.time() for i in pbar: pass print("w/o set_postfix_str: {:.2f}".format(time.time() - start)) pbar = tqdm(range(N), total=N, desc="N") start = time.time() for i in pbar: pass pbar.set_postfix_str(s="{}".format(i)) print("w set_postfix_str: {:.2f}".format(time.time() - start))
运行输出:
N: 100%|██████████| 10000/10000 [00:00<00:00, 1239195.20it/s]
w/o set_postfix_str: 0.01
N: 100%|██████████| 10000/10000 [00:12<00:00, 774.67it/s, 9999]
w set_postfix_str: 12.91
已尝试设置tqdm的miniters参数,但未取得优化效果,需要提升set_postfix_str的运行速度。
原因说明
set_postfix_str方法默认携带refresh=True参数,每次调用都会强制立即触发终端输出刷新,完全绕过tqdm自带的miniters、mininterval刷新频率限制。终端IO操作本身开销很高,逐迭代触发刷新会产生大量无效IO,直接拖慢整体运行速度,这也是单独设置miniters不生效的核心原因。
优化方法
- 给
set_postfix_str传入refresh=False参数
该配置下方法只会更新后缀存储的内容,不会立刻触发终端重绘,刷新动作交还给tqdm按照初始化时设置的miniters(每迭代多少次刷新一次)、mininterval(每多少秒最多刷新一次)规则自动执行,从根源减少无效IO。
示例修改:
该修改下运行耗时会和不调用后缀更新的版本基本持平,仅存在毫秒级差异。# 初始化时可同时配置刷新间隔,比如每0.1秒最多刷新一次 pbar = tqdm(range(N), total=N, desc="N", mininterval=0.1) start = time.time() for i in pbar: pass # 关闭强制刷新 pbar.set_postfix_str(s="{}".format(i), refresh=False) - 优先使用
set_postfix方法传递指标
如果是展示键值对形式的计算指标,直接用tqdm内置的set_postfix方法即可,不需要手动拼接字符串。该方法自带格式化优化,默认就不会强制逐次刷新,性能比手动拼字符串调用set_postfix_str更好,示例:pbar.set_postfix(iter=i, loss=current_loss, refresh=False) - 手动控制更新频率
也可以自行加判断逻辑,每隔固定迭代次数、或者固定时间间隔才调用一次后缀更新方法,减少调用次数自然就能降低性能开销,比如每迭代100次才更新一次后缀。
内容的提问来源于stack exchange,提问作者biock
相关产品推荐
相关产品推荐

