多线程Python脚本本地文件写入丢失或被覆盖问题排查
问题出在**bannerbear函数引用了全局的file变量**,多线程并发执行时,循环中的file变量会被不同线程迭代覆盖,导致多个线程同时写入同一个文件名,最终出现文件被覆盖或写入丢失的情况。单线程时file变量不会被并发修改,所以没有问题。
修复步骤:
- 给
bannerbear函数添加filename参数,让每个线程传入自己处理的文件名,避免共享变量冲突 - 调用
bannerbear时,传入当前线程处理的file参数 - (可选)如果
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
相关产品推荐
相关产品推荐

