You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用tqdm结合concurrent.futures并行任务时进度条混乱的原因及解决办法

使用tqdm结合concurrent.futures并行任务时进度条混乱的原因及解决办法

我来帮你搞定这个进度条混乱的问题!你遇到的情况主要是两个原因:一是你在任务函数calc内部已经创建了进度条,同时在外部又额外创建了一组进度条,导致同一位置有两个进度条互相干扰;二是多线程环境下,多个tqdm实例同时往终端输出,没有做线程同步,导致输出错乱。

咱们直接修改代码来解决,关键改动点我会一一说明:

修改后的完整代码

from math import factorial
from decimal import Decimal, getcontext
from concurrent.futures import ThreadPoolExecutor, as_completed
from tqdm import tqdm
import time

def calc(n_digits, pos, total, lock):
    # 计算迭代次数
    n = int(n_digits + 1 / 14.181647462725477)
    n = n if n >= 1 else 1

    # 设置精度
    getcontext().prec = n_digits + 1

    t = Decimal(0)
    pi = Decimal(0)
    deno = Decimal(0)

    # 使用共享锁保证线程安全,指定唯一位置
    for k in tqdm(range(n), 
                  position=pos, 
                  desc=f"Job {pos + 1} of {total}", 
                  leave=True, 
                  dynamic_ncols=True,
                  lock=lock):
        t = ((-1) ** k) * (factorial(6 * k)) * (13591409 + 545140134 * k)
        deno = factorial(3 * k) * (factorial(k) ** 3) * (640320 ** (3 * k))
        pi += Decimal(t) / Decimal(deno)

    pi = pi * Decimal(12) / Decimal(640320 ** Decimal(1.5))
    pi = 1 / pi

    return pi

def parallel_with_concurrent_futures():
    n_threads = 3
    tasks = [1200, 1700, 900, 1400]

    # 创建一个全局锁,供所有tqdm实例共享
    tqdm_lock = tqdm.get_lock()

    with ThreadPoolExecutor(max_workers=n_threads) as executor:
        # 提交任务时传入锁
        futures = {executor.submit(calc, n, pos, len(tasks), tqdm_lock): pos for pos, n in enumerate(tasks)}
        for future in as_completed(futures):
            pos = futures[future]
            try:
                result = future.result()
                # 可以在这里打印结果或者做其他处理
                # print(f"\nJob {pos + 1} completed, result length: {len(str(result))}")
            except Exception as e:
                print(f"\nJob {pos + 1} failed with error: {e}")

if __name__ == "__main__":
    parallel_with_concurrent_futures()

关键改动说明

  • 移除外层重复的进度条:原来你在外部创建的progress_bars完全是多余的,因为calc函数内部的循环已经用tqdm生成了进度条,重复创建会导致同一位置的输出冲突。
  • 添加线程安全锁:通过tqdm.get_lock()获取一个全局锁,传给每个任务里的tqdm实例,这样多个线程的进度条输出会被同步,不会出现交错、乱码的情况。
  • 保留唯一的进度条位置:每个任务的进度条通过pos参数指定唯一的终端行位置,完成后的进度条会保留在终端(因为leave=True),和你最开始想要的效果一致。
  • 去掉手动关闭进度条的操作:tqdm在循环结束后会自动处理进度条的状态,不需要手动调用close(),避免额外的输出干扰。

这样修改后,你运行代码就能一直保持像第一张图那样清晰的进度条展示,任务完成后进度条也会正常保留,不会出现混乱的情况。

备注:内容来源于stack exchange,提问作者Simd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 13:22:59