奇妙なことに、あなたが見ているのは予期された動作です。Python ドキュメントのプロファイラー セクションの紹介ではprofile
、cProfile
. あなたが見ている違いは、呼び出し方ではなく、使用しているライブラリにあります。次のスクリプトを検討してください。
import profile
import cProfile
def nothing():
return
def main():
for i in xrange(1000):
for j in xrange(1000):
nothing()
return
cProfile.run('main()')
profile.run('main()')
show mainからの出力はcProfile
、実行に約 0.143 秒かかりますが、profile
亜種は 1.645 秒と報告されており、これは約 11.5 倍長くなります。
ここで、スクリプトを次のように変更しましょう。
def nothing():
return
def main():
for i in xrange(1000):
for j in xrange(1000):
nothing()
return
if __name__ == "__main__":
main()
そして、プロファイラーでそれを呼び出します:
python -m プロファイル test_script.py
メインの実行に 1.662 秒を報告します。
python -m cProfile test_script.py
メインの実行に 0.143 秒を報告します。
cProfile
これは、プロファイラーを起動する方法が、 と の間に見られた不一致とは何の関係もないことを示していますprofile
。この違いは、2 つのプロファイラーが関数呼び出しや戻り値などの「イベント」を処理する方法によって発生します。どちらの場合も、実行中のコード全体にソフトウェア フックがあり、コールバックをトリガーしてこれらのイベントを追跡し、イベントのカウンターを更新したり、タイマーを開始または停止したりします。ただし、profile
モジュールはこれらすべてのイベントを Pythonでネイティブに処理します。つまり、インタープリターはコードを離れ、コールバックを実行し、戻ってコードを続行する必要があります。
cProfile
(プロファイリング コールバックを実行する) でも同じことが発生する必要がありますが、コールバックが C で記述されているため、はるかに高速です。2 つのモジュール ファイルprofile.pyとcProfile.pyを見ると、いくつかの違いが示されます。
- profile.pyは 610 行ですが、cProfile.pyはわずか 199 行です。ほとんどの関数は C で処理されます。
- profile.pyは主に Python ライブラリを使用しますが、cProfile.pyは C コード ファイルである「_lsprof」をインポートします。ソースはここで見ることができます。
- profile.pyの
Profile
クラスは他のどのクラスからも継承されませんが (111 行目)、cProfile.pyのクラス(66 行目)は C ソース ファイルに実装されている から継承されます。Profile
_lsprof.Profiler
ドキュメントcProfile
に記載されているように、ほとんどがCで実装されているため、すべてが高速であるため、一般的にはこれが適しています。
余談ですが、profile
キャリブレーションを行うことで のパフォーマンスを向上させることができます。それを行う方法の詳細は、ドキュメントで入手できます。これらすべてがどのように/なぜこのようになっているのかについての詳細は、決定論的プロファイリングと制限に関する Python ドキュメント セクションにあります。
TL;DR
cProfile
その名前が示すように、ほとんどが C で実装されているため、はるかに高速です。これはprofile
、ネイティブ Python ですべてのプロファイリング コールバックを処理する必要があるモジュールとは対照的です。プロファイラーをコマンド ラインから呼び出すか、スクリプト内で手動で呼び出すかは、2 つのモジュール間の時間差に影響しません。