Python 中的进度跟踪
最后修改日期:2025 年 4 月 1 日
对于 Python 中的长时间运行操作,跟踪进度至关重要。本教程介绍了实现进度跟踪的各种方法,从简单的控制台指示器到高级 GUI 进度条。
我们将探讨多种方法,包括流行的 tqdm 库、手动进度条、基于回调的跟踪以及与不同 Python 框架的集成。每种方法都有其针对不同用例的优势。
基本控制台进度
简单的进度跟踪可以使用 print 语句来实现。
import time
total = 100
for i in range(total):
# Process item here
time.sleep(0.1) # Simulate work
# Update progress
progress = (i + 1) / total * 100
print(f"\rProgress: {progress:.1f}%", end="")
print("\nDone!")
此示例显示了在控制台应用程序中跟踪进度的最简单方法。\r 回车符将光标移动到行首,从而可以在同一行上更新进度。end="" 参数阻止换行。
虽然基本,但此方法可以在任何地方工作,并且不需要任何依赖项。它非常适合只需要显示完成百分比的简单脚本。sleep 调用模拟演示的处理时间。
使用 tqdm 显示进度条
tqdm 库以最少的代码提供高级进度条。
from tqdm import tqdm
import time
# Basic progress bar
for i in tqdm(range(100)):
time.sleep(0.02) # Simulate work
# With description and unit
items = ["apple", "banana", "cherry", "date"]
for item in tqdm(items, desc="Processing", unit="item"):
time.sleep(0.5)
tqdm 自动显示进度条,其中包含剩余估计时间、每秒迭代次数等。desc 参数添加描述,而 unit 指定正在处理的内容。
该库自动处理所有格式化和更新。它可以在 Jupyter notebooks 和常规控制台中工作。tqdm 是 Python 中大多数进度跟踪需求的常用解决方案。
手动进度条
对于自定义需求,您可以构建自己的进度条。
import sys
import time
def draw_progress(progress, width=50):
filled = int(width * progress)
bar = "[" + "=" * filled + " " * (width - filled) + "]"
sys.stdout.write(f"\r{bar} {progress*100:.1f}%")
sys.stdout.flush()
total = 200
for i in range(total):
time.sleep(0.02)
draw_progress((i + 1) / total)
print("\nComplete!")
此实现使您可以完全控制进度条的外观。draw_progress 函数创建一个指定宽度的条,其填充与当前进度成比例。
使用 sys.stdout.write 和 flush 可确保平滑更新。当您需要自定义格式或无法使用外部库时,此方法非常有用。
文件操作的进度跟踪
使用回调跟踪文件操作期间的进度。
import shutil
import os
def copy_with_progress(src, dst):
total = os.path.getsize(src)
copied = 0
def callback(chunk):
nonlocal copied
copied += len(chunk)
progress = copied / total * 100
print(f"\rCopying: {progress:.1f}%", end="")
shutil.copyfileobj(
open(src, "rb"),
open(dst, "wb"),
callback=callback
)
print("\nDone!")
copy_with_progress("large_file.dat", "copy.dat")
此示例演示了文件复制操作期间的进度跟踪。回调函数接收正在复制的数据块,并相应地更新进度显示。
该方法适用于任何类文件对象,使其可用于网络传输或自定义数据处理管道。 nonlocal 关键字允许从嵌套函数修改 copied 计数器。
线程进度更新
对于后台任务,请使用线程来分别更新进度。
import threading
import time
import random
class ProgressTracker:
def __init__(self, total):
self.progress = 0
self.total = total
self.running = True
def update(self):
while self.running and self.progress < self.total:
self.progress += random.randint(1, 5)
time.sleep(0.1)
def display(self):
while self.running and self.progress < self.total:
pct = self.progress / self.total * 100
print(f"\rProgress: {pct:.1f}%", end="")
time.sleep(0.05)
print("\nDone!")
tracker = ProgressTracker(100)
worker = threading.Thread(target=tracker.update)
display = threading.Thread(target=tracker.display)
worker.start()
display.start()
worker.join()
tracker.running = False
display.join()
此模式将工作和进度显示分离到不同的线程中。ProgressTracker 类使用共享的进度变量在它们之间进行协调。
running 标志确保干净的关闭。此方法非常适合 GUI 应用程序,或者当正在完成的工作本身无法轻松报告进度时。
Jupyter 中的进度跟踪
Jupyter notebooks 支持丰富的进度显示。
from IPython.display import display
import ipywidgets as widgets
import time
progress = widgets.FloatProgress(
value=0, min=0, max=100, description="Loading:"
)
display(progress)
for i in range(100):
time.sleep(0.05)
progress.value = i + 1
IPython 提供特殊的 widget 用于交互式进度跟踪。FloatProgress widget 创建一个实时更新的可视条。
此方法在 notebooks 中创建专业外观的进度指示器。这些 widget 与 Jupyter 的显示系统无缝集成,并支持其他功能,例如样式设置和多个进度条。
使用多进程进行进度跟踪
使用共享内存跨多个进程跟踪进度。
import multiprocessing
import time
def worker(shared_progress, total_work):
for i in range(total_work):
time.sleep(0.1)
with shared_progress.get_lock():
shared_progress.value += 1
def display_progress(shared_progress, total):
while True:
with shared_progress.get_lock():
current = shared_progress.value
progress = current / total * 100
print(f"\rProgress: {progress:.1f}%", end="")
if current >= total:
break
time.sleep(0.1)
if __name__ == "__main__":
total_tasks = 100
progress = multiprocessing.Value("i", 0)
processes = []
for _ in range(4):
p = multiprocessing.Process(
target=worker,
args=(progress, total_tasks//4)
)
processes.append(p)
p.start()
display_progress(progress, total_tasks)
for p in processes:
p.join()
print("\nAll tasks completed!")
此示例演示了跨多个工作进程的进度跟踪。共享的 Value 在进程之间协调进度更新。
get_lock() 上下文管理器可确保线程安全的更新。对于分布在多个核心上的 CPU 密集型任务,同时仍提供进度反馈,此模式至关重要。
使用 Tkinter 的 GUI 进度条
为桌面应用程序创建图形进度条。
import tkinter as tk
from tkinter import ttk
import threading
import time
class ProgressApp:
def __init__(self, root):
self.root = root
self.progress = ttk.Progressbar(
root, orient="horizontal",
length=300, mode="determinate"
)
self.progress.pack(pady=20)
self.button = tk.Button(
root, text="Start Task",
command=self.start_task
)
self.button.pack()
def start_task(self):
self.button.config(state="disabled")
thread = threading.Thread(target=self.run_task)
thread.start()
self.monitor(thread)
def run_task(self):
for i in range(100):
time.sleep(0.05)
self.progress["value"] = i + 1
def monitor(self, thread):
if thread.is_alive():
self.root.after(100, lambda: self.monitor(thread))
else:
self.button.config(state="normal")
root = tk.Tk()
app = ProgressApp(root)
root.mainloop()
此 Tkinter 应用程序显示一个专业的进度条,该进度条在后台任务期间更新。线程可防止长时间操作期间 GUI 冻结。
monitor 方法定期检查线程状态。此模式确保响应迅速的 UI,同时为需要一段时间才能完成的操作提供视觉反馈。
使用 Flask 进行 Web 进度跟踪
在 Web 应用程序中实现进度跟踪。
from flask import Flask, jsonify, render_template_string
import time
import threading
app = Flask(__name__)
progress_data = {"value": 0, "total": 100}
def long_running_task():
for i in range(progress_data["total"]):
time.sleep(0.1)
progress_data["value"] = i + 1
@app.route("/")
def index():
return render_template_string("""
<h1>Progress Demo</h1>
<div id="progress">0%</div>
<button onclick="startTask()">Start</button>
<script>
function startTask() {
fetch("/start").then(() => pollProgress());
}
function pollProgress() {
fetch("/progress").then(r => r.json())
.then(data => {
document.getElementById("progress").innerHTML =
data.value + "%";
if (data.value < 100) {
setTimeout(pollProgress, 500);
}
});
}
</script>
""")
@app.route("/start")
def start():
thread = threading.Thread(target=long_running_task)
thread.start()
return "Started"
@app.route("/progress")
def progress():
return jsonify({
"value": progress_data["value"],
"total": progress_data["total"]
})
if __name__ == "__main__":
app.run(threaded=True)
此 Flask 应用程序演示了基于 Web 的进度跟踪。前端轮询后端以获取进度更新,而任务在后台线程中运行。
template_string 显示一个最小的 HTML 界面。在生产中,您将分离模板并添加错误处理。threaded=True 选项允许 Flask 处理并发请求。
最佳实践
- 选择正确的方法: CLI 使用 tqdm,Jupyter 使用 widget
- 更新频率:不要太频繁地更新(至少 100 毫秒)
- 线程安全:使用锁保护共享的进度变量
- 错误处理:确保进度在出错时停止
- 用户体验:提供清晰的标签和完成消息
资料来源
作者
我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。
列出所有 Python 教程。