openpyxlでlxmlの有無によるエクセル作成時間の変化を試してみた

openpyxlでlxmlの有無によるエクセル作成時間の変化を試してみた

lxmlの効果、ありました。
Clock Icon2025.03.28

私たち製造ビジネステクノロジー部では、製造業に関するエンドユーザや事業会社さんに対して、システムやサービスを事業会社さんと一緒に作成・運用しています。そんな製造業において、PLCなどのデータをエクセルにまとめるため、プログラムでエクセルを作る機会がありました。
openpyxlで大量データのあるエクセルを作ると時間が掛かっていたので、公式ドキュメントの内容で改善するかを試してみました。

大量のデータをダンプする場合は、lxmlがインストールされていることを確認してください。

https://openpyxl.readthedocs.io/en/3.1.3/optimized.html

おすすめの方

  • AWS Lambdaでopenpyxlとlxmlを利用したい方
  • lxmlの有無によるエクセル作成時間の変化を知りたい方

Lambdaをデプロイする

次の4パターンで確認します。

lxml write-mode
なし なし
なし あり
あり なし
あり あり

sam init

sam init \
    --runtime python3.11 \
    --name lambda-openpyxl-sample \
    --app-template hello-world \
    --no-tracing \
    --no-application-insights \
    --structured-logging \
    --package-type Zip

requirements.txtにライブラリを記載する

lxml なし

requirements.txt
openpyxl

lxml あり

requirements.txt
openpyxl
lxml

SAMテンプレート

メモリは、2048MBで試します。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: lambda-openpyxl-sample

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: lambda-openpyxl-sample-function
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.11
      MemorySize: 2048
      Timeout: 900
      Architectures:
      - x86_64

  HelloWorldFunctionLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}

Lambdaコード(write-mode なし)

app.py
import openpyxl
import time

def lambda_handler(event, context):
    wb = openpyxl.Workbook()
    ws = wb.active

    # 50万行 x 10列のデータを書き込む
    begin_write = time.perf_counter()
    for i in range(500_000):
        ws.append([f"{i}-{j}" for j in range(0, 10)])
    end_write = time.perf_counter()
    print(f"Write time: {(end_write - begin_write)} s")

    begin_save = time.perf_counter()
    wb.save("/tmp/hello_world.xlsx")
    end_save = time.perf_counter()
    print(f"Save time: {end_save - begin_save} s")

if __name__ == "__main__":
    lambda_handler(None, None)

Lambdaコード(write-mode あり)

app.py
import openpyxl
import time

def lambda_handler(event, context):
    wb = openpyxl.Workbook(write_only=True)
    ws = wb.create_sheet()

    # 50万行 x 10列のデータを書き込む
    begin_write = time.perf_counter()
    for i in range(500_000):
        ws.append([f"{i}-{j}" for j in range(0, 10)])
    end_write = time.perf_counter()
    print(f"Write time: {(end_write - begin_write)} s")

    begin_save = time.perf_counter()
    wb.save("/tmp/hello_world.xlsx")
    end_save = time.perf_counter()
    print(f"Save time: {end_save - begin_save} s")

if __name__ == "__main__":
    lambda_handler(None, None)

デプロイ

sam build --use-container
sam deploy

Lambdaを実行してみる

4個のパターンでLambdaを実行します。

aws lambda invoke \
    --function-name lambda-openpyxl-sample-function \
    output.txt

実行結果

lxmlがあると実行時間が短くなりました。

lxml write-mode 行追加[s] 保存[s] 全体[s] メモリ使用量[MB]
なし なし 23.5 69.0 92.5 1857
あり なし 23.8 49.6 73.4 1863
なし あり 74.9 4.8 79.7 356
あり あり 52.3 4.8 57.1 361

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.