pyinstallerを使ったpythonコードのexe化と、処理時間の評価(onefileオプションの有無を含む)

概要

pyinstallerを使ってpythonスクリプトのexe化することがままあるが、exe化すると速度が遅くなるように感じる。(特に--onefileオプションを入れて一つのファイルにパッケージ化した場合)
しかし、どの程度の速度低下があるのか定量的に測定した例がなかったので、まとめておく。

また、事前知識として、pyinstallerを使ったpythonスクリプトのexe化、windowsでのプログラムの処理時間の測定方法についても言及する。

事前知識1:pythonスクリプトのexe化(pyinstaller)

まずは、事前知識として、pyinstallerを使ってpythonスクリプトをexe化する方法をまとめる。

Pyinstallerのインストールはpipで一発。

Pip install pyinstaller

exeファイル化する際は、以下のようにすれば良い。
普通にexe化すると大量のdllが生成されるが、オプションで--onefileとすると一つのexeファイルにまとめてくれる。また、-wオプションを加えるとコマンドプロンプトが表示されなくなるため、GUIを作り込んだプログラムは-wをつけると良い。
ここで、単純にexe化した場合と、一つのexeファイルにまとめた場合で速度がどのように変化するのか、が今回の着目点となる。

pyinstaller.exe [スクリプト名] --clean

事前知識2:windowsでのプログラムの処理時間の測定(powershell)

次に、Windowsでプログラムが起動してから、終了するまでの時間測定の仕方をまとめる。
今回は、以下のとおりPowershellを使うことで、プログラムの処理時間を測定することとする。

powershell -Command "Measure-Command {実行したいスクリプト}"

最もシンプルなアプリケーションでの比較

まずは、処理がpassのみのスクリプトでの処理時間の比較を行った。その結果を以下表に示す。
意外なことに、exe化したほうが速度が速く、exe化後の速度を比較しても、デフォルトとonefile版で有意な差は見られなかった。
これだけを見るとonefile化した方が良いように思えるが、実際に使ってみた感覚とは大きく異なる結果である為、大きなライブラリをインポートした場合にどうなるか、次章でさらに確認を行った。

pythonスクリプトをそのまま実行 exe化(デフォルト) exe化(onefile)
177.6098ms 104.6429ms 109.2499ms

評価したスクリプト(最もシンプルなもの)

pass

numpyをインポートしたスクリプトで比較

次に、一般的な使用を想定して、numpyをインポートして行列計算をさせてみた。
この場合の処理時間を以下表に示す。これを見ると、pythonスクリプトをそのまま起動する分には、前章の実験と速度はほとんど変わらないが、exe化したものはかなり時間が増えていることがわかる。
特にonefile化した場合の処理時間は、pythonスクリプトをそのまま起動するのと比較して、約50倍の処理時間がかかっており、大きなライブラリをインポートする際は、onefile化すべきでないことがわかる。

pythonスクリプトをそのまま実行 exe化(デフォルト) exe化(onefile)
179.9112ms 633.2128ms 6989.3388ms

評価したスクリプト(numpyをインポートしたのもの)

import numpy as np
from numpy.random import rand

N = 200
a = np.array(rand(N, N))
b = np.array(rand(N, N))
c = np.array([[0] * N for _ in range(N)])

結論・まとめ

pyinstallerを使ってpythonスクリプトのexe化を行う際、ライブラリをインポートすると速度が低下する。この低下の度合いは、--onefileオプションを入れて一つのexeファイル化した際により顕著になる。
このことから、exe化する場合は、以下の点に注意する必要があると考えられる。
・なるべくインポートするライブラリは減らす
・基本的に--onefileオプションは使用しない。特にインポートするライブラリが多い場合は使用不可