看來,之所以函數調用次數不同的是,因爲myscript.py
導入模塊不會再次導入我第二次運行代碼。
獲得一致結果的第一種方法是在執行分析之前導入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))
我發現的第二種方法是刪除我執行腳本時註冊的所有模塊。好處是,如果我在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)
我無法複製它,但是如果沒有'myscript.py'中的代碼就很困難。 – eandersson
這可能很遙遠,但是有沒有任何情況下你正在使用任何緩存裝飾/記憶或類似的東西? (另外,我只使用了CPython,所以我不確定其他任何實現是否執行任何memoization/caching)。 – nvlass
我認爲它與我正在分析的腳本中有'import'語句有關。 –