cProfile 导入
cProfile with imports
我目前正在学习如何使用 cProfile
,我有一些疑问。
我目前正在尝试分析以下脚本:
import time
def fast():
print("Fast!")
def slow():
time.sleep(3)
print("Slow!")
def medium():
time.sleep(0.5)
print("Medium!")
fast()
slow()
medium()
我执行命令python -m cProfile test_cprofile.py
,结果如下:
Fast!
Slow!
Medium!
7 function calls in 3.504 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 3.504 3.504 test_cprofile.py:1(<module>)
1 0.000 0.000 0.501 0.501 test_cprofile.py:10(medium)
1 0.000 0.000 0.000 0.000 test_cprofile.py:3(fast)
1 0.000 0.000 3.003 3.003 test_cprofile.py:6(slow)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
2 3.504 1.752 3.504 1.752 {time.sleep}
但是,当我使用顶部的 pylab 导入 (import pylab
) 编辑脚本时,cProfile
的输出非常大。我试图使用 python -m cProfile test_cprofile.py | head -n 10
来限制行数,但是我收到以下错误:
Traceback (most recent call last):
File "/home/user/anaconda/lib/python2.7/runpy.py", line 162, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/home/user/anaconda/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/home/user/anaconda/lib/python2.7/cProfile.py", line 199, in <module>
main()
File "/home/user/anaconda/lib/python2.7/cProfile.py", line 192, in main
runctx(code, globs, None, options.outfile, options.sort)
File "/home/user/anaconda/lib/python2.7/cProfile.py", line 56, in runctx
result = prof.print_stats(sort)
File "/home/user/anaconda/lib/python2.7/cProfile.py", line 81, in print_stats
pstats.Stats(self).strip_dirs().sort_stats(sort).print_stats()
File "/home/user/anaconda/lib/python2.7/pstats.py", line 360, in print_stats
self.print_line(func)
File "/home/user/anaconda/lib/python2.7/pstats.py", line 438, in print_line
print >> self.stream, c.rjust(9),
IOError: [Errno 32] Broken pipe
有人可以帮助解决与此类似情况的正确程序吗,我们有一个 import pylab
或另一个模块在 cProfile
上生成如此高的输出信息?
我不知道有什么方法可以像您一样通过 运行 cProfile
模块直接从命令行进行选择性分析。
但是,您可以通过修改代码以显式 import
模块来完成此操作,但您必须自己完成所有操作。下面是如何对您的示例代码执行此操作:
(注:以下代码兼容Python2和3。)
from cProfile import Profile
from pstats import Stats
prof = Profile()
prof.disable() # i.e. don't time imports
import time
prof.enable() # profiling back on
def fast():
print("Fast!")
def slow():
time.sleep(3)
print("Slow!")
def medium():
time.sleep(0.5)
print("Medium!")
fast()
slow()
medium()
prof.disable() # don't profile the generation of stats
prof.dump_stats('mystats.stats')
with open('mystats_output.txt', 'wt') as output:
stats = Stats('mystats.stats', stream=output)
stats.sort_stats('cumulative', 'time')
stats.print_stats()
mystats_output.txt
之后的文件内容:
Sun Aug 02 16:55:38 2015 mystats.stats
6 function calls in 3.522 seconds
Ordered by: cumulative time, internal time
ncalls tottime percall cumtime percall filename:lineno(function)
2 3.522 1.761 3.522 1.761 {time.sleep}
1 0.000 0.000 3.007 3.007 cprofile-with-imports.py:15(slow)
1 0.000 0.000 0.515 0.515 cprofile-with-imports.py:19(medium)
1 0.000 0.000 0.000 0.000 cprofile-with-imports.py:12(fast)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
更新:
您可以通过使用 context manager method to automate things. Instead of adding a method with a name like enable_profiling()
to do this, I've implemented it so that you can just call the class instance in a with
语句派生您自己的 Profile
class 来更轻松地启用分析。只要退出 with
语句控制的上下文,分析就会自动关闭。
这是 class:
from contextlib import contextmanager
from cProfile import Profile
from pstats import Stats
class Profiler(Profile):
""" Custom Profile class with a __call__() context manager method to
enable profiling.
"""
def __init__(self, *args, **kwargs):
super(Profile, self).__init__(*args, **kwargs)
self.disable() # Profiling initially off.
@contextmanager
def __call__(self):
self.enable()
yield # Execute code to be profiled.
self.disable()
使用它而不是普通的 Profile
对象看起来像这样:
profiler = Profiler() # Create class instance.
import time # Import won't be profiled since profiling is initially off.
with profiler(): # Call instance to enable profiling.
def fast():
print("Fast!")
def slow():
time.sleep(3)
print("Slow!")
def medium():
time.sleep(0.5)
print("Medium!")
fast()
slow()
medium()
profiler.dump_stats('mystats.stats') # Stats output generation won't be profiled.
with open('mystats_output.txt', 'wt') as output:
stats = Stats('mystats.stats', stream=output)
stats.strip_dirs().sort_stats('cumulative', 'time')
stats.print_stats()
# etc...
因为它是一个 Profile
subclass,所有基本 class' 方法,例如 dump_stats()
仍然可用,如图所示。
当然,您可以更进一步,添加例如一种生成统计数据并以某种自定义方式格式化它们的方法。
如果您稍微更改脚本,那么在不分析导入的情况下分析脚本会容易得多。
test_cprofiler.py
import time
import pylab
def fast():
print("Fast!")
def slow():
time.sleep(3)
print("Slow!")
def medium():
time.sleep(0.5)
print("Medium!")
def main():
fast()
slow()
medium()
if __name__ == "__main__":
main()
profiler.py
import cProfile
import test_cprofiler
cProfile.run("test_cprofiler.main()")
运行 为:
python profiler.py
产生以下输出:
Fast!
Slow!
Medium!
8 function calls in 3.498 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 3.498 3.498 <string>:1(<module>)
1 0.000 0.000 2.998 2.998 run.py:11(slow)
1 0.000 0.000 3.498 3.498 run.py:15(main)
1 0.000 0.000 0.000 0.000 run.py:4(fast)
1 0.000 0.000 0.500 0.500 run.py:7(medium)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
2 3.498 1.749 3.498 1.749 {time.sleep}
我目前正在学习如何使用 cProfile
,我有一些疑问。
我目前正在尝试分析以下脚本:
import time
def fast():
print("Fast!")
def slow():
time.sleep(3)
print("Slow!")
def medium():
time.sleep(0.5)
print("Medium!")
fast()
slow()
medium()
我执行命令python -m cProfile test_cprofile.py
,结果如下:
Fast!
Slow!
Medium!
7 function calls in 3.504 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 3.504 3.504 test_cprofile.py:1(<module>)
1 0.000 0.000 0.501 0.501 test_cprofile.py:10(medium)
1 0.000 0.000 0.000 0.000 test_cprofile.py:3(fast)
1 0.000 0.000 3.003 3.003 test_cprofile.py:6(slow)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
2 3.504 1.752 3.504 1.752 {time.sleep}
但是,当我使用顶部的 pylab 导入 (import pylab
) 编辑脚本时,cProfile
的输出非常大。我试图使用 python -m cProfile test_cprofile.py | head -n 10
来限制行数,但是我收到以下错误:
Traceback (most recent call last):
File "/home/user/anaconda/lib/python2.7/runpy.py", line 162, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/home/user/anaconda/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/home/user/anaconda/lib/python2.7/cProfile.py", line 199, in <module>
main()
File "/home/user/anaconda/lib/python2.7/cProfile.py", line 192, in main
runctx(code, globs, None, options.outfile, options.sort)
File "/home/user/anaconda/lib/python2.7/cProfile.py", line 56, in runctx
result = prof.print_stats(sort)
File "/home/user/anaconda/lib/python2.7/cProfile.py", line 81, in print_stats
pstats.Stats(self).strip_dirs().sort_stats(sort).print_stats()
File "/home/user/anaconda/lib/python2.7/pstats.py", line 360, in print_stats
self.print_line(func)
File "/home/user/anaconda/lib/python2.7/pstats.py", line 438, in print_line
print >> self.stream, c.rjust(9),
IOError: [Errno 32] Broken pipe
有人可以帮助解决与此类似情况的正确程序吗,我们有一个 import pylab
或另一个模块在 cProfile
上生成如此高的输出信息?
我不知道有什么方法可以像您一样通过 运行 cProfile
模块直接从命令行进行选择性分析。
但是,您可以通过修改代码以显式 import
模块来完成此操作,但您必须自己完成所有操作。下面是如何对您的示例代码执行此操作:
(注:以下代码兼容Python2和3。)
from cProfile import Profile
from pstats import Stats
prof = Profile()
prof.disable() # i.e. don't time imports
import time
prof.enable() # profiling back on
def fast():
print("Fast!")
def slow():
time.sleep(3)
print("Slow!")
def medium():
time.sleep(0.5)
print("Medium!")
fast()
slow()
medium()
prof.disable() # don't profile the generation of stats
prof.dump_stats('mystats.stats')
with open('mystats_output.txt', 'wt') as output:
stats = Stats('mystats.stats', stream=output)
stats.sort_stats('cumulative', 'time')
stats.print_stats()
mystats_output.txt
之后的文件内容:
Sun Aug 02 16:55:38 2015 mystats.stats
6 function calls in 3.522 seconds
Ordered by: cumulative time, internal time
ncalls tottime percall cumtime percall filename:lineno(function)
2 3.522 1.761 3.522 1.761 {time.sleep}
1 0.000 0.000 3.007 3.007 cprofile-with-imports.py:15(slow)
1 0.000 0.000 0.515 0.515 cprofile-with-imports.py:19(medium)
1 0.000 0.000 0.000 0.000 cprofile-with-imports.py:12(fast)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
更新:
您可以通过使用 context manager method to automate things. Instead of adding a method with a name like enable_profiling()
to do this, I've implemented it so that you can just call the class instance in a with
语句派生您自己的 Profile
class 来更轻松地启用分析。只要退出 with
语句控制的上下文,分析就会自动关闭。
这是 class:
from contextlib import contextmanager
from cProfile import Profile
from pstats import Stats
class Profiler(Profile):
""" Custom Profile class with a __call__() context manager method to
enable profiling.
"""
def __init__(self, *args, **kwargs):
super(Profile, self).__init__(*args, **kwargs)
self.disable() # Profiling initially off.
@contextmanager
def __call__(self):
self.enable()
yield # Execute code to be profiled.
self.disable()
使用它而不是普通的 Profile
对象看起来像这样:
profiler = Profiler() # Create class instance.
import time # Import won't be profiled since profiling is initially off.
with profiler(): # Call instance to enable profiling.
def fast():
print("Fast!")
def slow():
time.sleep(3)
print("Slow!")
def medium():
time.sleep(0.5)
print("Medium!")
fast()
slow()
medium()
profiler.dump_stats('mystats.stats') # Stats output generation won't be profiled.
with open('mystats_output.txt', 'wt') as output:
stats = Stats('mystats.stats', stream=output)
stats.strip_dirs().sort_stats('cumulative', 'time')
stats.print_stats()
# etc...
因为它是一个 Profile
subclass,所有基本 class' 方法,例如 dump_stats()
仍然可用,如图所示。
当然,您可以更进一步,添加例如一种生成统计数据并以某种自定义方式格式化它们的方法。
如果您稍微更改脚本,那么在不分析导入的情况下分析脚本会容易得多。
test_cprofiler.py
import time
import pylab
def fast():
print("Fast!")
def slow():
time.sleep(3)
print("Slow!")
def medium():
time.sleep(0.5)
print("Medium!")
def main():
fast()
slow()
medium()
if __name__ == "__main__":
main()
profiler.py
import cProfile
import test_cprofiler
cProfile.run("test_cprofiler.main()")
运行 为:
python profiler.py
产生以下输出:
Fast!
Slow!
Medium!
8 function calls in 3.498 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 3.498 3.498 <string>:1(<module>)
1 0.000 0.000 2.998 2.998 run.py:11(slow)
1 0.000 0.000 3.498 3.498 run.py:15(main)
1 0.000 0.000 0.000 0.000 run.py:4(fast)
1 0.000 0.000 0.500 0.500 run.py:7(medium)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
2 3.498 1.749 3.498 1.749 {time.sleep}