十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python读取10万行Excel耗时实测:pandas与openpyxl对比

Python读取10万行Excel耗时实测:pandas与openpyxl对比 在处理 Excel 表格时经常会冒出一个灵魂拷问用 Python 读取大量数据到底有多快特别是面对那种动不动就几万行、十万行甚至更多的表格不同库的耗时差异可能非常大。这篇文章直接围绕“Python 常见库读取 10 万行 Excel 耗时”这个主题做一轮实测记录帮你扫掉选型盲区。先说结论如果你只是偶尔读一次几万行的 Excel很多库的耗时差异感知不明显但如果你要批量处理几十个文件或者经常做数据集成、报表导入读取耗时就直接影响任务吞吐。对于 10 万行数据量级pandas 这类数据分析库往往更稳但 xlsx 格式本身的解析速度也会拖后腿而一些偏底层的库在某些场景下反而更快但使用门槛更高。不同库之间真正拉开的差距主要体现在文件格式、单次读取方式、是否带样式解析、以及后续数据处理需求上。这篇文章适合这几类人正在做 Python Excel 处理技术选型的开发者、需要批量导入报表的数据分析同学、以及想搞明白为什么 openpyxl 越跑越慢的初学者。下面按实际测试顺序拆一遍不吹性能只讲怎么测、怎么判、怎么避坑。1. 先确认测试对象和痛点10 万行到底卡在哪1.1 为什么单看读取速度会失真在做库对比之前先要明确一个问题读取 Excel 的耗时并不只取决于“文件里有多少行”而是由下面这些因素一起决定文件格式xlsx、xls、xlsm、xlsb、csv底层解析逻辑完全不同。单元格内容是纯数字、短文本还是大量长文本、公式、超链接、批注。单元格数量10 万行乘以 10 列就是 100 万个单元格这跟 10 万行乘以 3 列完全不是同一个量级。是否保留样式部分库默认不关心样式部分库即使不主动读取样式也会在加载时付出额外解析成本。是否读取全部数据有时只需要某一列但很多库没法做到真正的列裁剪。很多所谓“读 10 万行慢”的报错和体验本质不是行数问题而是单元格总量和解析方式问题。建议测试时先统一这些口径不然不同库的对比结果很难说明问题。1.2 常见 Python Excel 库的适用场景在正式做耗时对比之前先把几个常见库按适用场景理一遍。这样后面的测试结果放在具体场景里才有意义。pandas数据分析首选。它本身不是专门解析 Excel 的库而是通过 openpyxl、xlrd 等底层库作为引擎。优点是 API 友好读进来直接是 DataFrame后续统计和处理非常方便。openpyxl专门处理 xlsx 的库能读写、能处理样式、公式、图表。缺点就是单纯读大文件时速度不算出色。xlrd老牌库2.0 之后只支持 .xls不再支持 .xlsx。如果你的历史文件是 .xls可以用它。xlwt写 .xls 用的读取场景用不到。pyxlsb用于读取 .xlsb 二进制格式这种格式在部分企业报表系统里比较常见。csv 标准库严格来说不是 Excel 文件但很多导出数据实际上就是 CSV。处理超大表格时速度优势明显。做对比测试前先确认文件后缀和自己需要处理的格式。如果源文件是 xlsx那测试范围重点可以放在 pandas 和 openpyxl 上如果有 xls 文件再考虑 xlrd。2. 搭建测试环境统一格式、统一数据口径2.1 环境准备实测不用特别高的服务器配置普通办公电脑就能看趋势。建议先确认三个基础项Python 版本、库版本、测试文件格式。python --version pip list | findstr -i pandas openpyxl xlrd xlsxwriter如果没有安装相关库可以按需安装pip install pandas openpyxl xlrd xlsxwriter这里有个容易忽略的点pandas 读取不同格式时需要额外安装对应的引擎依赖。比如读取 xlsx 依赖 openpyxl读取 xls 依赖 xlrd读取 xlsb 依赖 pyxlsb。只装 pandas 就直接读 xlsx 也能跑通但底层引擎版本不合适时会报错或者性能不稳定。2.2 生成 10 万行测试文件为了测试统一我一般会先自己生成一个 10 万行、10 列的 xlsx 文件内容尽量模拟普通业务数据比如订单 ID、日期、区域、商品名称、数量、单价、金额、备注等字段。下面是用 openpyxl 生成测试文件的示例这里只用于造数据不属于耗时对比范围from openpyxl import Workbook import random import datetime wb Workbook() ws wb.active ws.title sales_data headers [order_id, order_date, region, product, quantity, unit_price, amount, remark] ws.append(headers) product_list [键盘, 鼠标, 显示器, U盘, 硬盘, 耳机, 摄像头, 音箱] region_list [华东, 华北, 华南, 西南, 西北] remark_list [正常单, 加急单, 退款单, 测试单, ] for i in range(1, 100001): quantity random.randint(1, 20) unit_price random.randint(20, 500) order_date datetime.date(2023, random.randint(1, 12), random.randint(1, 28)).strftime(%Y-%m-%d) row [ fNO{i:08d}, order_date, random.choice(region_list), random.choice(product_list), quantity, unit_price, quantity * unit_price, random.choice(remark_list), ] ws.append(row) wb.save(test_10w_rows.xlsx) print(生成完成)生成的文件大约包含 100 万个单元格大小通常在 40MB 到 80MB 之间具体取决于文本长度和压缩情况。生成时要注意一点如果以后要对比文件体积对读取速度的影响尽量在生成后固定文件不要反复生成字符串长度差异很大的版本。备注列如果全是超长文本读取耗时和文件大小会明显上升。2.3 测试脚本的统一口径为了减少误差每次测试都只调用一次读取方法并记录从开始加载到数据可用的时间。用 time.perf_counter 是比较稳的做法。import time import pandas as pd from openpyxl import load_workbook start time.perf_counter() df pd.read_excel(test_10w_rows.xlsx, sheet_namesales_data, engineopenpyxl) cost time.perf_counter() - start print(fpandas openpyxl 读取耗时: {cost:.3f} 秒) print(f读取结果: {df.shape})这里建议每次测试前都重新启动一个 Python 进程不要在一个进程里连续测多次。原因是操作系统会缓存文件页面连续第二次读取通常会比第一次快。要对比就统一跑“冷启动”场景或者多次取均值。3. 单文件读取实测分格式测出真实差距3.1 xlsx 格式下 openpyxl 与 pandas 的表现在 xlsx 格式下最常见的读取方式有两种直接使用 openpyxl 的 load_workbook以及通过 pandas 的 read_excel。从实操体验上说openpyxl 直接加载后得到的是 Workbook 对象还要再通过 worksheet.iter_rows 或 worksheet.values 获取数据。pandas 则直接返回 DataFrame后续处理更方便。在 10 万行、10 列的数据测试中我会分别跑以下两种方式# 方式一openpyxl 直接读取为列表 from openpyxl import load_workbook start time.perf_counter() wb load_workbook(test_10w_rows.xlsx, read_onlyTrue, data_onlyTrue) ws wb[sales_data] rows list(ws.iter_rows(values_onlyTrue)) cost time.perf_counter() - start print(fopenpyxl read_only 读取耗时: {cost:.3f} 秒) print(f总行数: {len(rows)}) wb.close() # 方式二pandas 读取 start time.perf_counter() df pd.read_excel(test_10w_rows.xlsx, sheet_namesales_data, engineopenpyxl) cost time.perf_counter() - start print(fpandas read_excel 读取耗时: {cost:.3f} 秒)从个人实测经验看openpyxl 必须开启 read_onlyTrue 才适合读大文件。如果只是普通模式 load_workbook耗时和内存占用都会明显上升。pandas 在底层使用 openpyxl 时也是走文件流和行迭代但封装后做了 DataFrame 转换所以最终耗时和 openpyxl 直接读列表不一定谁快谁慢要看机器配置和 xlsx 内部的 XML 结构。需要注意一个反直觉的点同样是 10 万行xlsx 不是一种固定“格式”它是一片 XML 压缩包。单元格数量相同但字符串长、公式数量多、单元格格式多都可能导致读取耗时差异达到 50% 以上。3.2 xls 格式下 xlrd 的测试结果差异性如果手头还有历史遗留的 .xls 文件可以用 xlrd 来读。xlrd 2.0 之后只支持 .xls不支持 .xlsx这一点要特别注意。import xlrd workbook xlrd.open_workbook(test_old.xls) sheet workbook.sheet_by_name(sales_data) rows [] for r in range(sheet.nrows): rows.append(sheet.row_values(r)).xls 格式的问题是单元格数量一大遍历速度会明显降下来。很多开发者在旧系统迁移时发现 Python 读 .xls 比读 .xlsx 慢这不是错觉是因为两种格式的底层存储和定位方式不一样。建议长期维护的报表尽量转成 .xlsx 或者直接输出 CSV一方面读取库选择更多另一方面整体处理生态更现代。3.3 csv 格式作为对照组既然标题叫“Excel”有人会问 CSV 算不算。严格来说不算 Excel 格式但如果你在做报表导出、数据交换CSV 可能是更合适的载体。import csv start time.perf_counter() with open(test_10w_rows.csv, r, encodingutf-8) as f: reader csv.reader(f) rows [row for row in reader] cost time.perf_counter() - start print(fcsv 标准库读取耗时: {cost:.3f} 秒)CSV 没有格式化样式、公式、单元格类型等复杂结构本质就是纯文本。所以它的读取速度天然占优势。但要注意用 Excel 打开 CSV 再另存为 xlsx 后数据会出现明显的格式推断问题比如订单号变成科学计数法、日期格式被重排。这块属于业务处理不属于库性能问题。3.4 建议记录的数据维度做对比时不要只记录耗时至少要同时记录总耗时文件大小总行数、总列数CPU 型号或大致配置内存占用有条件的情况下看峰值库版本号把这些记下来后续换机器、换数据时就能快速判断耗时增长是数据问题还是环境问题。4. 数据遍历场景中的性能差异4.1 读取和遍历要分开看待很多测试只记录“读取完成”的时间但在真实业务里读完之后往往还要做遍历、筛选、聚合、写入新文件这些操作。比如拿到 10 万行 Excel我们需要按区域统计金额或者根据备注内容筛选异常单。这时候不同库的数据结构差异就开始影响效率。pandas 的优势在于读完之后就可以用向量化操作处理数据基本不需要写逐行 for 循环。比如按区域分组统计销售额df[amount] df[quantity] * df[unit_price] result df.groupby(region)[amount].sum().reset_index() print(result)这类向量化计算量在 10 万行时非常快通常不到 1 秒。但如果换成 openpyxl 直接读成列表再用 Python 原生循环去遍历计算耗时可能达到十几秒甚至更久。所以如果业务“读取之后还要做数据加工”强烈建议直接采用 pandas不要自己在列表数据上写循环。4.2 逐行处理与高性能场景的取舍在需要逐行处理的场景比如清洗脏数据、调用外部接口补充信息、根据规则判断是否命中某条件pandas 的 iterrows 和普通 for 循环速度都比较慢。原因是 DataFrame 的每一行需要被转换为 Series这个开销在 10 万行时会被放大。更稳的做法是先把 DataFrame 转为 list 或 numpy 数组再做循环。这里有一个对比示例# 不推荐的写法迭代 DataFrame 行 for idx, row in df.iterrows(): total row[quantity] * row[unit_price] # 更稳的写法先转 numpy再遍历 arr df[[quantity, unit_price, amount]].to_numpy() total_list [] for qty, price, amount in arr: total_list.append(qty * price)第二种写法虽然也没法打败纯向量化但在逐行处理场景下明显比 iterrows 快。很多初学者总以为慢是因为读取库不行实际是遍历方式选错了。5. 并行读取与批量任务别把耗时问题变成资源灾难5.1 要不要用多进程或线程池遇到几十个 10 万行 Excel 文件有人第一反应是开线程池、多进程并行读取。这个思路可行但 Excel 文件的瓶颈一般不仅仅是 CPU还有磁盘 IO 和内存占用。如果文件存放在机械硬盘上开太多并行进程反而会让磁盘寻道时间变长整体耗时不一定下降甚至可能上升。建议先把串行读取一遍记录单文件平均耗时和峰值内存。只有当磁盘整体吞吐还有富余时才考虑用多进程读取。例如用 concurrent.futures 的 ProcessPoolExecutor 做多文件并行读取from concurrent.futures import ProcessPoolExecutor def read_one(file): return pd.read_excel(file, sheet_namesales_data, engineopenpyxl) files [a.xlsx, b.xlsx, c.xlsx] with ProcessPoolExecutor(max_workers3) as executor: results list(executor.map(read_one, files))如果单个文件读取时内存占用已经接近 2GB 到 3GB并行任务就要非常克制。10 万行 xlsx 在 pandas 中转成 DataFrame 后内存通常要占用几百 MB多个文件同时加载可能直接吃掉 8GB 到 16GB 内存。5.2 批量处理时的失败重试与命名策略批量场景里能不能稳定跑完比单个文件跑多快更重要。建议顺序是先写一个函数只处理单文件入参是文件路径出参是统计结果或写好的新文件。单独用 3 个文件做冒烟测试确认路径、编码、输出目录没问题。再跑全量打印文件处理进度。单个文件报错时记录错误信息并跳过不要中断整个任务。一个常见的坑是输出文件命名冲突。如果用原文件名加固定后缀多个并行任务同时写文件时可能出现覆盖或写入失败。建议用“原文件名 时间戳 随机短码”的方式避免冲突并且中间结果统一写到独立目录。6. 从耗时结果倒推选型建议6.1 低频小文件场景怎么选都不太重要如果你的任务是每天只读几千行 Excel或者只是偶尔帮业务同事跑一次数据那直接用 pandas 就可以了不用纠结底层库。6.2 十万行以上常规表格优先 pandas10 万行、几十列以内的常规表格pandas 读取虽然没有特别极致但读写之后的处理效率很高。真正慢的部分往往是在业务层用了不合适的循环而不是读取本身。6.3 只读取不处理考虑 read_only 手工迭代如果你的场景只是把 xlsx 里的数据抽出来转存到数据库或者另一个文件不要求做复杂计算那么直接使用 openpyxl 的 read_only 模式并按行迭代可能比 pandas 更省内存也更容易控制节奏。6.4 超大文件或生产级方案考虑 csv 或换格式当文件行数超过几十万、甚至上百万行时xlsx 格式本身会越来越吃力。此时更合理的方向不是继续遴选 Python 库而是把上游数据导出为 CSV或用专业的列式存储格式。这不是库的问题是场景和格式的边界问题。7. 常见报错与耗时排查链路7.1 读取慢的通用排查步骤如果发现某个库读取 10 万行 Excel 特别慢先别急着下结论说这个库不行。按下面的顺序排查先看文件后缀确认是 xlsx、xls 还是 csv。再看文件大小如果 10 万行文件有几百 MB说明里面可能包含大量内嵌图片、隐藏工作表、样式或格式冗余。确认是否开启了隐藏对象或加密工作表。有些 Excel 文件会因保护、缓存等因素导致解析变慢。检查 Python 环境是否是 32 位32 位进程内存访问上限会影响大文件处理。最后才考虑换库或调参。7.2 常见报错原因与处理ValueError: Excel file format cannot be determined文件后缀和真实格式不一致按实际格式匹配对应引擎。ModuleNotFoundError: No module named openpyxl底层引擎缺失安装对应依赖。MemoryError峰值内存过高改用 read_only 模式或分批读取。读取后日期变成数字Excel 日期序列值常见问题读取时不要急着处理先看原始数据。订单号或长数字变成科学计数法在 Excel 中查看时出现读到 pandas 后数字类型可能被转换需要将列转成字符串并保留位数。7.3 卡住时的正确观察方式如果读取文件时卡住先确认不是真的报错只是没打进度日志。常见做法是打开任务管理器或资源监视器看 CPU、内存、磁盘读写是否还在活动。如果 CPU 一直是单核 100%说明解析过程还在进行如果磁盘读写和 CPU 都基本为 0那可能是卡死在等待某个外部资源上比如网络盘或杀毒软件扫描。读取网络共享目录上的 Excel 时建议先复制到本地临时目录再解析网络文件锁和延迟会成为隐藏耗时项。8. 留下几个关键参考点如果让我给一个比较务实的启动配置通常会这样场景推荐方案原因常规数据分析pandas openpyxl 引擎API 友好读取后处理效率高只读取不加工openpyxl read_only 模式内存占用更低历史 .xls 文件xlrd现阶段只能靠它大批量导出或交换csv解析代价最低在你自己的环境里建议把“读取数据、转换为可用结构、完成一次简单加工”三者连起来计时而不是只测读取 API 的返回时间。这样得到的数据才更像真实业务耗时。最后再强调几个容易踩的坑不要一上来就用线程池读 Excel先看磁盘和内存不要在循环里面频繁打开和关闭工作簿能一次读完就一次读完不要以为用了 pandas 就一定快如果数据后处理写了很多原生 for 循环整体耗时可能比 openpyxl 直接读还糟糕。按我自己的习惯拿到一个 Excel 处理任务第一件事是先看文件样例和行数第二件事是确认输出要求第三件事才选定读取库。先把入口和出口弄清楚中间的耗时才能优化到点子上。
返回列表