3

Python スクリプトのプロファイリングに役立つインターフェイスを作成しています。profile.py source codeから Python スクリプトを実行するコードを借りました。同じコードを 2 回連続してプロファイリングすると、2 回目は異なる数の関数呼び出しが返されることに気付きました。たとえば、 で次のコードを実行しますmyscript.py

from cProfile import Profile
import sys
import os.path

for i in range(3):
    prof = Profile()

    progname = 'myscript.py'
    sys.path.insert(0, os.path.dirname(progname))
    with open(progname, 'rb') as fp:
        code = compile(fp.read(), progname, 'exec')
    globs = {
            '__file__': progname,
            '__name__': '__main__',
            '__package__': None,
            '__cached__': None,
            }
    prof.runctx(code, globs, None)
    prof.create_stats()
    print(len(prof.stats))

私にくれます

511
30
30

出力として。2回目に呼ばれる関数mushの数が少ないのはなぜですか? 正しい数字はどれ?両方とも同じ結果を得るにはどうすればよいですか?


myscript.py次のようになります。

import numpy
import numpy.linalg

if __name__ == '__main__':

    r = numpy.random.rand(1000, 1000)
    numpy.linalg.inv(r)
4

1 に答える 1

1

myscript.py関数呼び出し回数が異なるのは、コードを 2 回目に実行したときにインポートされたモジュールが再度インポートされないためと思われます。

myscript.py一貫した結果を得る最初の方法は、プロファイリングを実行する前にインポートすることです。ただし、インポートしたモジュールがインポート時に何らかのタスクを実行する場合、これはプロファイリングされないことを意味します。

prof = Profile()

progname = 'myscript.py'
sys.path.insert(0, os.path.dirname(progname))
modname, _ = os.path.splitext(os.path.basename(progname))
__import__(modname, globals(), locals(), [], 0)
with open(progname, 'rb') as fp:
    code = compile(fp.read(), progname, 'exec')
globs = {
        '__file__': progname,
        '__name__': '__main__',
        '__package__': None,
        '__cached__': None,
        }
prof.runctx(code, globs, None)
prof.create_stats()
print(len(prof.stats))

私が見つけた 2 番目の方法は、スクリプトを実行したときに登録されたすべてのモジュールを削除することです。利点は、GUI の実行中にソースを変更すると、変更が再ロードされることです。私が今持っている欠点は、必要なモジュールが前に削除されるため、一部の atexit 登録ハンドラーがクラッシュすることです。

prof = Profile()

progname = 'myscript.py'
sys.path.insert(0, os.path.dirname(progname))
with open(progname, 'rb') as fp:
    code = compile(fp.read(), progname, 'exec')
globs = {
        '__file__': progname,
        '__name__': '__main__',
        '__package__': None,
        '__cached__': None,
        }
modules = sys.modules.copy()
prof.runctx(code, globs, None)
newmodes = [modname for modname in sys.modules if modname not in modules]
for modname in newmodes:
    del sys.modules[modname]
prof.create_stats()
print(len(prof.stats))

最後に、私が見つけた最良の方法は、プロファイリングを別のプロセスで実行することです。

import concurrent.futures
import marshal
from cProfile import Profile
from pstats import Stats
import sys

progname = 'myscript.py'
with concurrent.futures.ProcessPoolExecutor() as executor:
    future = executor.submit(_run, progname)
    stats = Stats()
    stats.stats = marshal.loads(future.result())
    stats.get_top_level_stats()

def _run(progname):
    sys.path.insert(0, os.path.dirname(progname))

    with open(progname, 'rb') as fp:
        code = compile(fp.read(), progname, 'exec')
    globs = {
        '__file__': progname,
        '__name__': '__main__',
        '__package__': None,
    }
    prof = Profile()
    prof.runctx(code, globs, None)
    prof.create_stats()
    return marshal.dumps(prof.stats)
于 2013-04-16T16:49:40.727 に答える