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

Openpyxl并行处理问题:多子工作簿读写主工作簿数据丢失

多进程操作openpyxl主工作簿数据丢失问题解决

问题原因

多进程(包括Ray)的内存空间相互隔离,每个子进程会复制主进程中的master_workbook和ws1对象作为独立副本。子进程对副本的修改不会同步回主进程的原始对象,最终主进程保存的仍是未修改的原始工作簿,导致累加数据丢失。

解决方案

核心思路是让子进程仅负责读取子工作簿的数据,返回需要累加的数值集合,由主进程统一完成累加和写入操作,避免多进程直接操作同一个工作簿对象。


1. Python内置multiprocessing实现

from openpyxl import load_workbook, Workbook
from openpyxl.styles import NamedStyle
import multiprocessing

def read_child_data(file_path):
    # 子进程仅读取数据,返回单元格与对应数值的字典
    child_wb = load_workbook(filename=file_path, data_only=True, read_only=True)
    sheet = child_wb["Sheet1"]
    data = {}
    for i in range(0, 10):
        target_row = 12
        target_col = 2 + i
        # 读取子工作簿数据,空值默认设为0
        val = sheet.cell(row=10, column=2+i).value or 0
        data[(target_row, target_col)] = val
    child_wb.close()
    return data

if __name__ == "__main__":
    # 初始化主工作簿与样式
    master_workbook = Workbook()
    ws1 = master_workbook.active
    ws1.title = "Sample"

    # 定义并添加样式(补充你原有样式的具体配置)
    number_default_style = NamedStyle(name="number_default_style")
    # number_default_style.font = Font(...)
    # number_default_style.alignment = Alignment(...)
    master_workbook.add_named_style(number_default_style)

    # 子工作簿路径列表
    child_files = [
        "C:\\Somesamplefile1.xlsx",
        "C:\\Somesamplefile2.xlsx",
        "C:\\Somesamplefile3.xlsx"
    ]

    # 多进程读取所有子工作簿数据
    with multiprocessing.Pool(processes=3) as pool:
        results = pool.map(read_child_data, child_files)

    # 主进程统一累加并写入数据
    for cell_data in results:
        for (row, col), val in cell_data.items():
            current_val = ws1.cell(row=row, column=col).value or 0
            ws1.cell(row=row, column=col).value = current_val + val
            ws1.cell(row=row, column=col).style = "number_default_style"

    # 后续格式处理与保存
    master_workbook.save(filename="C:\\Someoutputfile.xlsx")

2. Ray实现

from openpyxl import load_workbook, Workbook
from openpyxl.styles import NamedStyle
import ray

ray.init()

@ray.remote
def read_child_data_ray(file_path):
    # Ray远程函数仅读取数据,返回结构化结果
    child_wb = load_workbook(filename=file_path, data_only=True, read_only=True)
    sheet = child_wb["Sheet1"]
    data = {}
    for i in range(0, 10):
        target_row = 12
        target_col = 2 + i
        val = sheet.cell(row=10, column=2+i).value or 0
        data[(target_row, target_col)] = val
    child_wb.close()
    return data

if __name__ == "__main__":
    # 初始化主工作簿与样式
    master_workbook = Workbook()
    ws1 = master_workbook.active
    ws1.title = "Sample"

    number_default_style = NamedStyle(name="number_default_style")
    # 补充样式具体配置
    master_workbook.add_named_style(number_default_style)

    child_files = [
        "C:\\Somesamplefile1.xlsx",
        "C:\\Somesamplefile2.xlsx",
        "C:\\Somesamplefile3.xlsx"
    ]

    # 提交Ray任务并获取结果
    futures = [read_child_data_ray.remote(file) for file in child_files]
    results = ray.get(futures)

    # 主进程统一累加写入
    for cell_data in results:
        for (row, col), val in cell_data.items():
            current_val = ws1.cell(row=row, column=col).value or 0
            ws1.cell(row=row, column=col).value = current_val + val
            ws1.cell(row=row, column=col).style = "number_default_style"

    master_workbook.save(filename="C:\\Someoutputfile.xlsx")
    ray.shutdown()

关键注意事项

  • 子进程/远程函数仅执行读操作,返回字典、列表等可序列化数据,避免传递openpyxl的工作簿/工作表对象。
  • 所有对主工作簿的写操作均在主进程中完成,确保操作的是同一个工作簿实例。
  • 若子工作簿数据量极大,可分块读取返回,避免内存占用过高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 20:57:17