Azure函数中XLSX转Parquet效率优化:pd.read_excel耗时过长求解
优化XLSX转Parquet的Azure函数处理速度
核心问题分析
85MB的XLSX文件用pandas.read_excel(openpyxl引擎)耗时20分钟,主要原因是:
- openpyxl解析XLSX的效率偏低,全量加载会占用大量内存
- Azure函数默认资源配额(128MB内存)不足,导致GC频繁、处理卡顿
- HTTP请求传输大文件本身会增加额外耗时
可行优化方案
1. 用并行框架分块读取XLSX(推荐Dask)
Dask支持分块读取大文件并并行处理,能大幅降低读取和转换时间,同时减少内存压力。
示例代码:
import dask.dataframe as dd import io import azure.functions as func from azure.storage.blob import BlobServiceClient def main(req: func.HttpRequest) -> func.HttpResponse: try: # 获取请求体中的XLSX字节流 xlsx_bytes = req.get_body() with io.BytesIO(xlsx_bytes) as fh: # 按10MB分块读取XLSX,自动并行处理 ddf = dd.read_excel(fh, engine='openpyxl', blocksize='10MB') # 初始化Azure Blob客户端 conn_str = "你的存储账户连接字符串" blob_service_client = BlobServiceClient.from_connection_string(conn_str) container_client = blob_service_client.get_container_client("目标容器名") # 将Parquet写入内存缓冲区,再上传到Blob with io.BytesIO() as parquet_buf: ddf.to_parquet(parquet_buf, engine='fastparquet', compression='snappy') parquet_buf.seek(0) blob_client = container_client.get_blob_client("输出文件名.parquet") blob_client.upload_blob(parquet_buf, overwrite=True) return func.HttpResponse("转换完成并已保存至Azure存储", status_code=200) except Exception as e: return func.HttpResponse(f"处理失败: {str(e)}", status_code=500)
2. 调整Azure函数资源配置
Azure函数的CPU配额与内存绑定,提升内存配额能直接提升处理速度:
- 进入函数应用的配置 → 常规设置
- 将内存大小从默认128MB调整为512MB或1GB(根据实际需求)
- 同时可调整超时时间(默认5分钟,处理大文件需设为30分钟左右)
3. 改用Blob触发模式(避免HTTP传输大文件)
直接通过Blob存储触发函数,跳过HTTP传输大文件的环节,进一步节省时间:
示例代码(Blob触发):
import azure.functions as func import dask.dataframe as dd import io from azure.storage.blob import BlobServiceClient def main(myblob: func.InputStream): # 初始化Blob客户端 conn_str = "你的存储账户连接字符串" blob_service_client = BlobServiceClient.from_connection_string(conn_str) output_container = blob_service_client.get_container_client("输出容器名") # 分块读取Blob中的XLSX文件 ddf = dd.read_excel(myblob, engine='openpyxl', blocksize='10MB') # 生成输出Parquet文件名(替换原XLSX后缀) output_filename = f"{myblob.name.rsplit('.', 1)[0]}.parquet" # 转换并上传Parquet with io.BytesIO() as parquet_buf: ddf.to_parquet(parquet_buf, engine='fastparquet', compression='snappy') parquet_buf.seek(0) output_blob = output_container.get_blob_client(output_filename) output_blob.upload_blob(parquet_buf, overwrite=True)
4. 优化pandas读取方式(轻量方案)
如果不想引入Dask,可使用openpyxl的只读模式减少内存占用:
import io import pandas as pd from openpyxl import load_workbook import azure.functions as func from azure.storage.blob import BlobServiceClient def main(req: func.HttpRequest) -> func.HttpResponse: try: xlsx_bytes = req.get_body() with io.BytesIO(xlsx_bytes) as fh: # 启用只读模式,只加载数据不保留格式信息 wb = load_workbook(fh, read_only=True, data_only=True) sheet = wb.active # 逐行读取数据并转换为DataFrame data = list(sheet.values) df = pd.DataFrame(data[1:], columns=data[0]) # 转换为Parquet并上传 conn_str = "你的存储账户连接字符串" blob_service_client = BlobServiceClient.from_connection_string(conn_str) container_client = blob_service_client.get_container_client("目标容器名") with io.BytesIO() as parquet_buf: df.to_parquet(parquet_buf, engine='fastparquet') parquet_buf.seek(0) blob_client = container_client.get_blob_client("输出文件名.parquet") blob_client.upload_blob(parquet_buf, overwrite=True) return func.HttpResponse("转换完成", status_code=200) except Exception as e: return func.HttpResponse(f"处理失败: {str(e)}", status_code=500)
效果预期
- 改用Dask+512MB内存配置,85MB的XLSX文件读取+转换时间可压缩至2-5分钟
- Blob触发模式能再节省1-2分钟的HTTP传输时间
内容的提问来源于stack exchange,提问作者harapalb
相关产品推荐
相关产品推荐

