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

多线程Python脚本本地文件写入丢失或被覆盖问题排查

多线程下BannerBear合成图文件写入被覆盖/丢失的解决方法

问题出在**bannerbear函数引用了全局的file变量**,多线程并发执行时,循环中的file变量会被不同线程迭代覆盖,导致多个线程同时写入同一个文件名,最终出现文件被覆盖或写入丢失的情况。单线程时file变量不会被并发修改,所以没有问题。

修复步骤:

  1. 给bannerbear函数添加filename参数,让每个线程传入自己处理的文件名,避免共享变量冲突
  2. 调用bannerbear时,传入当前线程处理的file参数
  3. (可选)如果bannerbear中的data变量依赖当前文件名,也要将data作为参数传入,避免共享数据带来的问题

修改后的关键代码:

# Check the result of the RemoveBG API request if ok write the file locally and upload to s3
if response.status_code == requests.codes.ok:
    with open(
        os.path.join(OUTPUT_DIR, os.path.splitext(file)[0] + ".png"), "wb"
    ) as out:
        out.write(response.content)

        # Open a file-like object using io.BytesIO
        image_data = io.BytesIO(response.content)

        # Upload the image data to S3
        s3.upload_fileobj(image_data, bucket_name, object_key)

        # Get the URL for the uploaded image
        image_url = f"https://{bucket_name}.s3.amazonaws.com/{object_key}"
        print(f"Image uploaded to S3: {image_url}")

        # pass the s3 url AND current filename to BannerBear
        bannerbear(image_url, file)  # 传入当前的file参数


# 修改bannerbear函数,添加filename参数
def bannerbear(photo_url, filename):
    # 注意:如果data变量依赖当前文件名,需要在这里重新构建或者作为参数传入,避免共享data的问题
    # Send a POST request to the endpoint URL
    responseBB = requests.post(endpoint_url, headers=headers, json=data)
    if responseBB.status_code == 200:
        # Print the URL of the generated image
        bb_image_url = responseBB.json()["image_url_jpg"]
        print(bb_image_url)
        # Write the image data to a file
        filedata = requests.get(bb_image_url)
        # 使用传入的filename参数生成文件名,不再引用全局file
        with open(
            os.path.join(OUTPUT_DIR, "bb", os.path.splitext(filename)[0] + ".jpg"), "wb"
        ) as f:
            f.write(filedata.content)
        print(f"BannerBear File Written: {os.path.splitext(filename)[0]}.jpg")
    else:
        # 输出错误时关联当前文件名,便于排查
        print(f"An error occurred for {filename}: {responseBB.status_code}")
        print(responseBB.json()["message"])


# 线程池部分代码不变
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
    for file in os.listdir(IMAGE_DIR):
        if file.endswith(".jpg") or file.endswith(".png"):
            executor.submit(process_image, file)

额外注意点:

  • 检查bannerbear中的data变量,如果data包含和当前处理图片相关的内容(比如动态替换模板中的图片URL),确保每个线程使用的data是独立的,不要共享全局的data对象,否则可能出现多线程数据污染的问题。
  • 可以给文件写入操作添加关联文件名的日志,更直观地跟踪每个线程的处理结果。

内容的提问来源于stack exchange,提问作者Matt Winer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:15:29