使用httpx AsyncClient搭配tqdm.asyncio下载进度条显示异常如何解决
问题根源
tqdm默认按迭代次数计数,每遍历到一个元素就自动+1,无法感知你迭代的chunk实际字节长度。因此不管你是否指定aiter_bytes的chunk_size,tqdm都认为每次仅下载了1字节,最终和你设置的总字节数total单位不匹配,出现进度、速度、剩余时间完全失真的问题。
正确实现方案
你需要手动控制进度条的更新量,每次遍历到chunk后,将实际接收的字节长度传给tqdm的update方法即可,参考代码如下:
import tqdm.asyncio async with self.http.stream(method='GET', url=download_url) as res: # 可选:校验请求响应正常,避免下载到错误内容 res.raise_for_status() # 如果未提前获取文件总大小,可从响应头读取(需要服务端返回Content-Length) total_size = int(res.headers.get("Content-Length", 0)) # 初始化异步tqdm,不直接绑定迭代器 async with tqdm.asyncio.tqdm( desc=name, unit="iB", unit_scale=True, unit_divisor=1024, total=total_size # 用你之前的size变量也可以,确保单位是字节即可 ) as pbar: # 用上下文管理器处理文件,避免忘记关闭 with open(file_path, "wb") as f: # chunk_size可根据需求调整,示例为1M async for chunk in res.aiter_bytes(chunk_size=1024 * 1024): write_len = f.write(chunk) # 手动更新进度,步进为实际写入的字节数 pbar.update(write_len)
关键说明
chunk_size可自由调整,不会影响进度统计的准确性,因为每次更新的是实际字节长度,和chunk大小无关- 你之前配置的
unit/unit_scale/unit_divisor参数无需修改,只要进度更新的单位和total的单位统一为字节,显示就会完全正常 - 如果服务端不返回
Content-Length头,total可以传0,此时tqdm会显示已下载的字节数和实时速度,但不会展示总进度条和剩余时间
内容的提问来源于stack exchange,提问作者unknown_horse
相关产品推荐
相关产品推荐

