3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Lambda】コンパイラ型言語をLambdaで扱ってみるついでにインタープリタ型言語と比較してみた

3
Last updated at Posted at 2026-05-23

はじめに

先日某所で Lambda を用いてコンパイル型とインタープリタ型の違いを比較するLTを聴きました。その際、そういえばコンパイル型の言語を Lambda で扱ったことがないな〜となりました。せっかくなので簡単に触ってみたいと思います。ついでに実行速度を測って比較もしてみます。

前提環境

検証時の手元環境は以下のとおりです。

  • macOS(Apple Silicon)
  • Node.js v25.2.1
  • AWS CDK v2.1124.1
  • Go 1.26.3
  • Python 3.12(計測スクリプト実行用)

コンパイラとインタープリタの違い

まず軽くおさらいです。

種別 変換タイミング 言語例
コンパイラ 実行前に一括で機械語へ変換 Go, Rust, C
インタープリタ 実行しながら 1 行ずつ解釈 Python, Ruby
JIT(ハイブリッド) 実行直前に機械語化 Java, JavaScript

コンパイラは「先に全部翻訳しておいて、あとは実行するだけ」、インタープリタは「翻訳しながら走る」というイメージです。

Lambda での実装イメージ

Lambda はリクエストが来るたびにコンテナを起動して関数を実行する仕組みなので、起動時に何が走るかでコールドスタート時間が変わります。

Go(コンパイル型)

手元で go build を走らせて機械語バイナリ(bootstrap)を作り、それを zip にして Lambda にデプロイします。Lambda 側では bootstrap をメモリに読み込んで実行するだけなので、追加の変換処理は発生しません。

[手元]                                   [Lambda]
main.go ──go build──→ bootstrap ──zip──→ ロードして実行するだけ

Python(インタープリタ型)

.py ファイルをそのまま zip して Lambda にデプロイします。Lambda 側では Python インタープリタを起動して、ハンドラを 1 行ずつ解釈しながら実行します。

[手元]              [Lambda]
handler.py ──zip──→ Python インタープリタが解釈して実行

実測の準備

計測する4パターン

最小構成だけだと、コンパイル型・インタープリタ型の差というよりは Lambda ランタイムの起動コストの比較になってしまいそうなので、AWS SDK を入れたケースも用意しました。

関数名 構成
go-minimal Go + aws-lambda-go のみ
go-aws Go + aws-lambda-go + aws-sdk-go-v2 (S3 client)
python-minimal Python のみ(標準ライブラリ)
python-boto3 Python + boto3 (S3 client)

すべて同じ条件で揃えます。

項目
リージョン us-east-1
アーキテクチャ arm64
メモリ 256 MB
Go ランタイム provided.al2023
Python ランタイム python3.12

Go の関数コード

最小構成です。

// go-minimal/main.go
package main

import (
	"context"
	"github.com/aws/aws-lambda-go/lambda"
)

type Response struct {
	Message string `json:"message"`
}

func handler(ctx context.Context) (Response, error) {
	return Response{Message: "hello from go-minimal"}, nil
}

func main() {
	lambda.Start(handler)
}

AWS SDK 込みの方は init() で S3 クライアントを初期化するようにしました。

// go-aws/main.go
import (
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/s3"
)

var s3Client *s3.Client

func init() {
	cfg, _ := config.LoadDefaultConfig(context.Background())
	s3Client = s3.NewFromConfig(cfg)
}

Python の関数コード

こちらも最小構成です。

# python-minimal/handler.py
def lambda_handler(event, context):
    return {"message": "hello from python-minimal"}

boto3 込みの方は、トップで import + クライアント初期化までを済ませます。これで初期化のコストが Init Duration に乗ります。

# python-boto3/handler.py
import boto3

s3_client = boto3.client("s3")

def lambda_handler(event, context):
    _ = s3_client
    return {"message": "hello from python-boto3"}

CDK でまとめてデプロイ

CDK(TypeScript)でスタックを書きました。

Go のビルドは CDK の bundling.local 機能で go build を呼び出すようにして、cdk deploy 一発で完結するようにしています。

// cdk/lib/cdk-stack.ts(抜粋)
function goBundling(srcDirName: string) {
  const srcDir = path.join(PROJECT_ROOT, srcDirName);
  return {
    image: lambda.Runtime.PROVIDED_AL2023.bundlingImage,
    local: {
      tryBundle(outputDir: string): boolean {
        execSync('go mod tidy', { cwd: srcDir, stdio: 'inherit' });
        execSync(
          `GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="-s -w" ` +
          `-o "${outputDir}/bootstrap" main.go`,
          { cwd: srcDir, stdio: 'inherit' }
        );
        return true;
      },
    },
    command: [
      'bash', '-c',
      'go mod tidy && GOOS=linux GOARCH=arm64 CGO_ENABLED=0 ' +
      'go build -ldflags="-s -w" -o /asset-output/bootstrap main.go',
    ],
  };
}

CDK部分は Claude Code に用意してもらいました。
これで簡単にデプロイできるようになってるんですね。

計測スクリプト(コールドスタートを誘発して10回計測)

Lambda のコールドスタートを観測するため、今回は各計測前に環境変数をユニークな値で更新しました。

環境変数は Lambda の関数設定の一部であり、設定更新後は新しい設定でイベントを処理する実行環境が用意されます。これにより、更新完了後の Invoke でコールドスタートを発生させやすくしています。

環境変数の更新によって既存の実行環境がすべて即座に破棄される、と公式に明記されているわけではありません。本記事ではコールドスタートを誘発しやすくするための実験的な手法として扱っています。

# scripts/measure.py(抜粋)
def force_cold_start(function_name: str, marker: str) -> None:
    lambda_client.update_function_configuration(
        FunctionName=function_name,
        Environment={"Variables": {"COLD_START_MARKER": marker}},
    )
    waiter = lambda_client.get_waiter("function_updated")
    waiter.wait(FunctionName=function_name)

この後で関数を invoke し、CloudWatch Logs の REPORT 行から Init Duration を取り出します。

REPORT_RE = re.compile(
    r"Duration: ([\d.]+) ms\s+"
    r"Billed Duration: (\d+) ms\s+"
    r"Memory Size: (\d+) MB\s+"
    r"Max Memory Used: (\d+) MB\s+"
    r"Init Duration: ([\d.]+) ms"
)

これを各関数で 10 回ずつ繰り返します。

実測結果

実行結果を整理してみると以下の表のようになりました。

関数 平均 中央値 最小 最大
Go(最小) 58.39 ms 60.57 ms 52.27 ms 62.24 ms
Go + AWS SDK 83.03 ms 85.15 ms 73.34 ms 95.45 ms
Python(最小) 80.77 ms 83.98 ms 67.60 ms 87.71 ms
Python + boto3 575.22 ms 538.32 ms 415.49 ms 789.81 ms

Python + boto3 だけ明らかに時間がかかっていますね。

考察

最小構成だけなら Go と Python はほぼ同じ

Go(58 ms)と Python(81 ms)の差は約 23 ms しかありません。

インタープリタ型は起動が重いと言われがちですが、Lambda の場合は Python インタープリタの起動自体はそんなに重い処理ではないようです。少なくともコンパイル型との差は数十 ms で、ほとんどのユースケースでは気にならないレベルだと思います。

Go は AWS SDK を入れても +25 ms しか増えない

Go(最小)58 ms → Go + AWS SDK 83 ms で、差は約 25 ms となっています。

これは「go build の時点で AWS SDK の依存関係はすべて単一バイナリに焼き込まれている」ためです。Lambda 側はバイナリをロードするだけなので、追加されるコストは「バイナリサイズが少し増えた分のロード時間」だけになります。

Python は boto3 を入れると約7倍重くなる

Python(最小)81 ms → Python + boto3 575 ms で、差は約 495 ms(約7倍)となりました。

import boto3 は毎回コールドスタートのタイミングで実行されます。boto3 は内部で大量の AWS サービス定義 JSON を読み込み、botocore がそれをもとに各サービスのクライアントクラスを動的に生成する仕組みになっています。import boto3 の1行の裏でこの初期化処理がまとめて走るため、コールドスタートに大きく上乗せされる形になります。

このように、Go と Python で同じく AWS SDK 込みの構成にしましたが、Go は +25 ms、Python は +495 ms かかることがわかりました。

コンパイル型とインタープリタ型の本質的な違いが Lambda のコールドスタート時間という形でわかりやすく観測できたと思います。

おわりに

以上、簡単ではありましたが、コンパイル型言語を Lambda で動かしてみるついでに、インタープリタ型言語との比較を行ってみました。個人的にはあまり実行時間をシビアに考える機会がなかったのですが、違いを知ることができてよかったです。

ありがとうございました。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?