Python下载大文件时tqdm进度条为何延迟至下载完成才显示,如何让其启动即展示
进度条延迟到下载完成才显示的问题修复
问题根因
你的实现存在两处逻辑错误,共同导致了进度条显示滞后:
- 错误的总文件大小取值逻辑
代码中写的total = float(content_length)存在明显问题:这个content_length既没有从当前带stream=True的下载响应中提取,也没有做空值兼容。实际运行时,这个变量要么是提前请求过程中遗留的旧值,要么是因为在走到下载循环前已经把响应流全部读取完毕,导致后续resp.iter_content直接进入空迭代,循环第一次就执行完所有流程,tqdm刚初始化就直接跳到100%,观感上就是文件下完了进度条才弹出来。
正确的取值应该直接从下载请求的响应头中读取总大小,兼容无返回头的异常场景:resp = requests.get(url, stream=True) # 从响应头获取文件总大小,获取失败时设置为0避免报错 total = float(resp.headers.get('Content-Length', 0)) - 终端输出缓冲阻塞
Python默认对终端输出启用块缓冲,tqdm的进度条是高频短间隔输出的内容,会被操作系统暂存在输出缓冲区里,不会实时刷新到终端界面。直到整个下载流程执行完毕,缓冲区因为程序运行结束被强制清空,攒了很久的进度条内容才一次性显示出来,给人“晚了很久才启动”的错觉。
这个问题可以通过以下方式解决:- 每次更新进度条后强制刷新输出缓冲区,避免内容暂存:
for data in resp.iter_content(chunk_size=1024): size = file.write(data) bar.update(size) bar.refresh() # 强制将当前进度推送到终端 - 不要把分块大小设得太小,当前代码用的
chunk_size=1024(1KB)会导致循环频率过高,更容易触发缓冲堆积,调整为1MB分块可以大幅减少循环次数,降低缓冲压力:# 1MB为一个下载块,平衡下载速度和进度更新频率 for data in resp.iter_content(chunk_size=1024 * 1024): - 关闭Python的输出缓冲,二选一即可:
- 运行程序时添加
-u参数,比如python -u main.py - 代码开头加全局配置:
import sys sys.stdout.reconfigure(line_buffering=True)
- 运行程序时添加
- 每次更新进度条后强制刷新输出缓冲区,避免内容暂存:
额外注意
下载带重定向的资源时,要确保requests默认的重定向跟随开关没有被关闭(allow_redirects=True是默认值,不要手动设为False),否则会拿到重定向跳转页的内容大小,而不是最终下载文件的真实大小,导致进度条计算偏差。
内容的提问来源于stack exchange,提问作者user13767678
相关产品推荐
相关产品推荐

