使用ThreadPoolExecutor(16个工作线程)处理Excel I/O任务时出现DataFrame缺失或为None的问题,但单线程可正常运行
使用ThreadPoolExecutor(16个工作线程)处理Excel I/O任务时出现DataFrame缺失或为None的问题,但单线程可正常运行
我最近碰到个头疼的生产问题,想跟大家唠唠:我每天要处理300-500个Excel文件,流程就是读取每个文件、清洗转换成pandas DataFrame,最后把所有DataFrame合并成一个大表。
用单线程(max_workers=1)跑的时候,简直顺得不行,每次所有文件都能顺利转成DataFrame,合并也没任何问题。但为了提速换成16个线程的ThreadPoolExecutor后,直接掉坑里了——300多个文件里,只有20-50个能生成可用的DataFrame,剩下的要么直接缺失,要么返回的是None,完全没法正常合并。
我梳理了几个大概率的原因和对应的解决思路,你可以挨个试试:
- Excel读取库的线程安全问题:pandas的
pd.read_excel底层依赖的openpyxl、xlrd这些库,很多时候不是完全线程安全的。16个线程同时抢着调用读取函数,很容易出现资源竞争,导致读取失败返回空值。
解决办法:给读取Excel的逻辑加个线程锁,同一时间只允许一个线程执行读取操作。示例代码大概是这样:import threading from concurrent.futures import ThreadPoolExecutor import pandas as pd # 定义全局读取锁 excel_read_lock = threading.Lock() def process_single_excel(file_path): with excel_read_lock: try: # 读取并清洗数据 df = pd.read_excel(file_path) # 这里加你的数据清洗逻辑,比如列处理、缺失值填充等 return df except Exception as e: # 捕获异常并打印,避免线程静默崩溃 print(f"处理文件 {file_path} 时出错:{str(e)}") return None - 异常捕获不到位:单线程时如果某个文件读取出错,会直接抛出异常让你察觉,但多线程下要是没加
try-except,线程会悄悄崩溃,返回的就是None,你还以为是DataFrame缺失。
解决办法:务必给每个线程的处理函数加上完整的异常捕获,把每个文件的错误信息打出来,这样就能精准定位是文件损坏、权限不足还是其他具体问题。 - 系统文件句柄耗尽:16个线程同时打开文件,可能一下子就把系统的文件句柄上限耗光了,后面的文件根本打不开,自然读不出DataFrame。
解决办法:先试试把线程数降到8个或者更低,看看情况有没有好转。如果确实是句柄问题,也可以临时调高系统的文件句柄限制(不同系统操作不同,比如Linux调ulimit,Windows改注册表,谨慎操作)。 - 依赖库版本存在bug:有些旧版本的pandas或者其依赖的Excel读取库,在多线程场景下有已知的兼容性bug,会导致读取失败。
解决办法:把pandas、openpyxl、xlrd这些库都升级到最新的稳定版,说不定就能把这个坑填上。
内容来源于stack exchange
相关产品推荐
相关产品推荐

