Python には zipimport という機能があり、モジュールを zip から import することができます。
標準ではネイティブコードの拡張モジュール (*.pyd) やそれらが使うダイナミックリンクライブラリ (*.dll) を zip に固めることはできませんが、py2exe によってできるようになります。
zip に固めるといまいちサイズが縮まない気がしたので 7z から import できるようなモジュールを作り、かなり適当なベンチマークを取ってみました。
zip の中身は
- pywin32 のほとんど
- twisted
- zope 3 の一部
- wxPython
ファイルは 2700 個ほど、ディレクトリは 300 個ほど
ソースコードを使用。コンパイルキャッシュ (*.py[co]) は未使用
7z は上記の zip と同じ内容を solid 形式で固めたもの
アーカイブサイズ[MiB] | メモリ使用量[KiB] | |
zip | 12.6 | 36,472 |
7z | 6.91 | 79,164 |
real[s] | CPU[s] | |
zip 1回目 | 1.187 | 1.175 |
zip 2回目 | 0.844 | 0.848 |
zip 3回目 | 0.875 | 0.870 |
zip 4回目 | 0.859 | 0.863 |
zip 5回目 | 0.860 | 0.866 |
7z 1回目 | 2.781 | 2.779 |
7z 2回目 | 2.734 | 2.741 |
7z 3回目 | 2.734 | 2.741 |
7z 4回目 | 2.609 | 2.615 |
7z 5回目 | 2.594 | 2.592 |
大分差があります。
一度 import してしまえば reload しない限り、キャッシュされるので動作速度への影響は少ないでしょう。しかしプログラムの起動にかかる時間は大きく増えてしまうでしょう。
7z はsolid 形式で圧縮すると単体のファイルとしての解凍はできず、ブロックとしてまとめられた複数のファイルを一気に展開し、その中から目的のファイルを取り出すことになります。だのでキャッシュを使わないとものすごく遅くなります。メモリ使用量に大きな差があるのはそのせいです。キャッシュを減らすことはできますが、当然その分だけ時間を取られます。
微妙。
ちなみに zip の圧縮に LZMA を使うというのもやってみました *1 が、10~20 % サイズが低減されるだけです。多くのアーカイバでは扱えないアーカイブ形式になってしまい、取り扱いが面倒になるだけ無駄な感じ。
*1:要するに 7z と同じようなものになる