AWS Lambda(Python)を手っ取り早く高速化する方法【cloudpack 大阪 BLOG】

aws lambdaでは、CPUの使用時間に対し100ミリ秒単位で課金されるため、処理を高速化できるとその分料金も下がります。今回は簡単にLambda(Python)を高速化する方法を紹介します。

方法

処理系をJITコンパイル機能を持つPyPyに変更します。
これだけです。特にソースを見なおすとかではないので手軽に試せます。

PyPyとは
PyPy(パイパイ)は、プログラミング言語Pythonの実装の1つであり、Pythonで記述されたPythonの処理系であることが特徴の1つである(セルフホスティング)。PyPyは、実行速度と効率、およびオリジナルのPython実装であるCPythonとの互換性に重点を置いている。

PyPy - Wikipedia

環境構成

OS:Amazon Linux
PyPy:5.1.1 x86_64:

PyPyのインストール

公式サイトではredhat系のバイナリが提供されていませんので、以下ページで提供されているportable-pypyをダウンロードします。今回は、「PyPy 5.1.1 x86_64」をダウンロードしました。
GitHub - squeaky-pl/portable-pypy: Portable 32 and 64 bit x86 PyPy binaries for many Linux distributions.

ファイル構成

ダウンロードしたpypy-5.1.1-linux_x86_64-portable.tar.bz2を解凍してpypyにリネームしておきます。

ファイル構成は以下のとおりです

├── lambda_function.py    ・・・lambdaから呼び出されてrun.shを実行する
├── run.sh       ・・・main_functionをpypyで実行する 
├── main_function.py  ・・・実際の処理が書かれたpython
└── pypy        ・・・portable-pypy
lambda_function.py

run.shを実行するだけのlambda関数です

# coding: utf-8
import commands

def _(cmd):
    return commands.getoutput(cmd)

def lambda_handler(event, context):
    main()

def main():
    print _('sh ./run.sh')
run.sh

pypyで対象のpythonを実行します。

#!/bin/sh

echo exec pypy
./pypy/bin/pypy main_function.py
main_function.py

実際に実行したい処理をここに記述します。
今回はパフォーマンス測定用に大量のリストを追加する処理としました。

# coding: utf-8

def main():
  rangelist = range(1,100000)

  for var in range(0, 100):
     func(rangelist)

  print('main func finish')

def func(rangelist):
    list = []
    for var in rangelist:
        list.append(var)

if __name__=='__main__':
    main()

ファイルを全て準備できれば、ディレクトリごとzipで固めてlambdaへアップします。pypy-portableの容量が大きいのでs3経由でないとアップできませんでした。

パフォーマンス結果

以下測定結果です。上記のmain_function.pyをデフォルトで実行した時とPyPyで実行した時とで、それぞれ5回測定して平均を取りました。PyPyの場合初回が遅くなるかと思いましたがあまり変わりませんでした。

PyPy デフォルト
1 5085.81 13523.69
2 5655.01 13497.07
3 4984.38 15315.06
4 4931.47 14630.05
5 4981.22 13615.74
平均 5127.57 14116.32

単位:ms

まとめ

今回のケースの場合、処理時間が約1/3になったのでかなりの高速化の効果がありました。
lambdaで重い処理を実行している場合など、PyPyでパフォーマンス改善を試しててみるのもいいかもしれません。
ただし、全てのケースで早くなるわけではなく処理が軽いlambdaで試した場合は、PyPyで実行した時のほうが逆に遅かったです。また、デフォルトのCpythonとは互換性がない部分もありますので、実際に切り替える場合はしっかりとテストが必要になると思います。今後、パフォーマンス改善が必要になった場合に、1つの手法として試してみたいと思います。