Python から最高のパフォーマンスを引き出そうとすると、ほとんどの開発者は、C 拡張機能を使用したり、プロファイリング ツールを熱心に実行したりして、すぐに複雑なアルゴリズムの修正に飛びつきます。ただし、Python スクリプトを即座に高速化する最も簡単で最も見落とされている方法の 1 つは、コマンド ライン フラグです。
私たちがチェックしているフラグは、最終的なロジックの実行に厳密に必要でないものをすべてダンプする、コンパイル時の強力なクリーンアップを実行するように Python に指示するスイッチです。
目に見えないところに隠された秘密のパフォーマンス向上
コマンド python を使用してスクリプトを実行する場合 -O script.py、Python の基本最適化モードをオンにします。これは、多くの開発者が見逃している機能です。特に、多くの人がアサート ステートメントを無害なデバッグ ヘルパーと見なしているためです。
これらのチェックはただトリガーされるのを待っているだけだと思うかもしれませんが、高スループットの多忙な運用環境では、これらの条件を継続的にチェックすると、特に頻繁にヒットするループ内にある場合、処理速度が大幅に低下する可能性があります。の -O flag は、ソース コードをバイトコードにコンパイルする方法を根本的に変更するように Python インタープリターに指示します。具体的には、アサーションを完全に破棄する出力を生成します。
コンパイラは、プログラムがロードされる前に、assert ステートメントを命令セットから削除します。これは、バイトコード ファイルがわずかに小さくなるというだけではなく、コードの実行中にこれらの条件を検証することに関連する計算オーバーヘッドが除去されます。
アサーションを取り除くことだけが問題ではありません。 -O フラグはそうです。組み込みのグローバル定数を強制することで、ランタイム環境を根本的に変更します。 __debug__ 偽に。通常、最適化フラグなしでは、 __debug__ デフォルトは true で、診断コード ブロックは次のように保護されます。 if __debug__: 走る。ただし、最適化がアクティブな場合、Python コンパイラーはそれらのブロック全体でデッド コードの削除を実行します。
の値以来、 __debug__ バイトコードの生成時に決定されるため、インタープリタはプログラムの実行を開始する前にスクリプトのロジック ツリーをトリミングします。開発診断のみを目的としたコード パスは完全に削除され、インタプリタが false であることがすでにわかっている条件文をチェックするサイクルを無駄にすることがなくなります。
基本的に、コンパイラはバイトコードへの変換中にこれらのセグメントを無視するだけなので、運用環境でのパフォーマンスに影響を与えることなく、ソース ファイルに診断インストルメンテーションを残すことで、Python コーディングの実践に従うことができます。
効率を最大化するためのバイトコードの除去
標準 -O フラグは素晴らしいですが、もっと攻撃的なものが必要な場合は、 -OO あなたのためのものです。バイトコードから docstring を完全に削除し、コンパイルされた出力を完全に変更することで、さらにレベルを上げています。
インタプリタが次を使用して実行されるとき -OO、モジュール、クラス、関数のドキュメントを定義する文字列リテラルがすべて破棄されるため、それらを __doc__ 属性は後ほど。最新の Python は PEP 488 に従っているため、これを実行すると、 .opt-2.pyc 通常のファイルとはまったく異なります .pyc キャッシュまたは .opt-1.pyc 基本的な最適化からのバージョン。
リソース消費を改善するために機能を交換していることを覚えておく必要があります。このプロセスにより、メモリ フットプリントと最終的なメモリ フットプリントの両方が大幅に縮小されます。 .pyc Python では、ロジックの実行に厳密には必要のないテキストに RAM を割り当てる必要がないためです。
大規模な開発者のデスクトップでは数メガバイトの節約は無意味に思えるかもしれませんが、コンテナ化された環境、マイクロサービス、または組み込みシステムを使用している場合、この削減は絶対に重要です。限られたハードウェア上でサービスが何千回も実行される可能性がある大規模な展開では、RAM の 1 メガバイト単位が非常に重要になります。
この最適化により、読み込み時間も全体的に大幅に短縮されます。これらのコンパイルされたバイトコード ファイルは小さいため、インタプリタがディスクからファイルを読み取るために必要な I/O オーバーヘッドが少なくなり、インポート中にモジュール構造を解析するために必要な CPU サイクルも少なくなります。これは、命令セット全体を適切で無駄のない状態に保つのに役立ちます。これは、起動速度が重要なコマンドライン インターフェイス ツールや存続期間の短いプロセスにまさに必要なものです。これはあなたをエリートにするための非常に賢いプログラミング手法です。
デメリットがないとしたら不思議ですが、デメリットはあります。イントロスペクションに依存するコードは、使用すると壊れます。 -OO。これは、doctest、pydoc、またはヘルプ テキストやランタイム ロジックを生成するために docstring を解析しようとするライブラリなどのツール用です。したがって、この積極的な最適化は、コードベースが実行時にドキュメントにアクセスする必要がないことがわかっている実稼働環境のデプロイメントにのみ保存する必要があります。
Python 環境の分離による高速起動
ボーナスとして、 -E flag は、実行コンテキストがクリーンであることを確認するためのコマンドライン オプションです。 Python インタープリターにすべてを完全に無視するように指示します。 PYTHON* 起動時の環境変数。複雑な開発セットアップでは、次のような変数が使用されます。 PYTHONPATH そして PYTHONHOME 通常は、Python がモジュールを検索する場所をカスタマイズするか、標準ライブラリの場所を定義します。
これは特定のユーザー構成では便利ですが、これらの変数により実際には、スクリプトが起動されるたびにインタープリターが追加のフォルダーをスキャンし、追加のファイル パスを解析することになります。これにより、通常、初期化プロセスに不要なオーバーヘッドが追加されます。
Pythonを実行すると、 -Eを使用すると、これらの検索をスキップし、インタープリターがローカル パス、ユーザー定義のディレクトリ、または特定のスクリプトに絶対に必要のないカスタム サイト パッケージを検索することで時間を無駄にすることがなくなります。このフラグは基本的に、ランタイム環境のローカライズされたリセット ボタンのように機能するため、スクリプトがより速く、よりクリーンに起動されます。
これを行う理由は、PYTHONPATH がマップされたネットワーク ドライブなどの多数のディレクトリで詰まっている場合、モジュールの解決が大幅に遅くなるからです。また、標準ライブラリを誤ってオーバーライドしたり、バージョンの競合を引き起こしたりする危険もあります。
公平を期すために、 -I このフラグは、ユーザー サイト ディレクトリも無効にし、現在のフォルダーをディレクトリから削除するため、さらに厳密な分離を実現します。 sys.pathしたがって、それは問題ない代替品です。しかし、 -E 特に環境変数ベクトルをターゲットとしています。これだけで必要な場合には、起動プロセスをサニタイズするには十分です。
Python インタープリターは、安全で診断の多いコードを取得し、実稼働向けに無駄のないコードにするための強力な組み込みツールを提供します。アプリケーションが重い運用負荷の下で実行されている場合、作成、デバッグ、テスト中に絶対に必要なこれらの機能はすべて、単なるオーバーヘッドになります。
Python の起動に使用するコマンドを変更するだけで、実際のソース コードに 1 行も手を加えることなく、速度、メモリ サイズ、起動速度が大幅に向上します。システム構成と単純なフラグ設定により、ビジネス ロジックの微細な最適化に何時間も費やすよりも、すぐにパフォーマンスが向上することがよくあります。