Python cProfile和profile之间的差异&x2014;为什么没有profile.profile.enable()方法?
在Python2.7和Python3.6中,我发现这是可行的:Python cProfile和profile之间的差异&x2014;为什么没有profile.profile.enable()方法?,python,Python,在Python2.7和Python3.6中,我发现这是可行的: from cProfile import Profile; p = Profile(); p.enable() …鉴于这引发了一个例外: from profile import Profile; p = Profile(); p.enable() # --> AttributeError: 'Profile' object has no attribute 'enable' 这让我感到惊讶,因为我认为(以及和的官方文档
from cProfile import Profile; p = Profile(); p.enable()
…鉴于这引发了一个例外:
from profile import Profile; p = Profile(); p.enable()
# --> AttributeError: 'Profile' object has no attribute 'enable'
这让我感到惊讶,因为我认为(以及和的官方文档)这两个模块应该提供相同的程序员接口:
profile
和cProfile
模块都提供以下功能:
class-profile.profile(timer=None,timeunit=0.0,subcalls=True,builtins=True)
enable()
开始收集配置文件数据
我错过了什么?使用profile.profile()
实例的正确方法是什么?在最新的文档中,他们已经解决了这一问题,指定enable()
和disable()
仅适用于cProfile
。使用profile.profile
,您需要使用run()
调用,而不是enable()
和disable()
。以下是每个项目的样本:
cProfile.Profile:
# cProfile.Profile -- control with enable() and disable()
from datetime import datetime
import cProfile, pstats, io
sortby = 'cumulative'
pr1 = cProfile.Profile(lambda: int(datetime.now().timestamp()*1000000), 0.000001)
pr1.enable()
list(x for x in range(int(10*10*10*10/10*10+10)))
pr1.disable()
s1 = io.StringIO()
ps1 = pstats.Stats(pr1, stream=s1).sort_stats(sortby)
ps1.print_stats()
print(s1.getvalue())
# profile.Profile -- control with run()
from datetime import datetime
import profile, pstats, io
sortby = 'cumulative'
pr2 = profile.Profile(datetime.now().timestamp, 0.000001)
pr2.run('list(x for x in range(int(10*10*10*10/10*10+10)))')
s2 = io.StringIO()
ps2 = pstats.Stats(pr2, stream=s2).sort_stats(sortby)
ps2.print_stats()
print(s2.getvalue())
配置文件。配置文件:
# cProfile.Profile -- control with enable() and disable()
from datetime import datetime
import cProfile, pstats, io
sortby = 'cumulative'
pr1 = cProfile.Profile(lambda: int(datetime.now().timestamp()*1000000), 0.000001)
pr1.enable()
list(x for x in range(int(10*10*10*10/10*10+10)))
pr1.disable()
s1 = io.StringIO()
ps1 = pstats.Stats(pr1, stream=s1).sort_stats(sortby)
ps1.print_stats()
print(s1.getvalue())
# profile.Profile -- control with run()
from datetime import datetime
import profile, pstats, io
sortby = 'cumulative'
pr2 = profile.Profile(datetime.now().timestamp, 0.000001)
pr2.run('list(x for x in range(int(10*10*10*10/10*10+10)))')
s2 = io.StringIO()
ps2 = pstats.Stats(pr2, stream=s2).sort_stats(sortby)
ps2.print_stats()
print(s2.getvalue())
以下是我观察到的两种形式之间的一些行为差异:
将把配置文件函数的输出推送到标准输出,而cProfile
不会profile
- 最终报告的
列的输出将略有不同文件名:lineno(函数)
通常会更容易地显示内置函数cProfile
- 然而,在我这里提供的示例中,传入函数实际上可以在
的输出中识别,而不是在profile
中识别——但是如果使用命名函数,它可以在两个分析器的输出中识别(尽管传入函数的参数仅在cProfile
的输出中可见)profile
- 然而,在我这里提供的示例中,传入函数实际上可以在
- 通过
和cProfile
运行相同的函数会产生稍微不同的结果。似乎profile
通常会少生成两个函数调用,并为同一个函数提供更高效的时间cProfile
- 使用探查器的可选自定义
和计时器
参数可以获得微秒精度,而不是默认的毫秒精度。然而,尝试使用这些方法似乎有一些警告:时间单位
的timeunit函数需要一个整数,而cProfile
需要一个浮点数。这意味着您不能将profile
直接与datetime.now().timestamp()
一起使用,而是必须先将其包装在lambda中以将其转换为完整整数cProfile
- 此外,由于某种原因,
似乎无法正确使用profile
格式,即使该格式符合预期。它将打印出负的时间值——我在下面展示。切换到lambda表单将其转换为整数没有帮助,因为datetime.now().timestamp()
需要浮点数profile
- 下面是
的输出,带有profile.profile
计时器,用于微秒设置datetime.now().timestamp()
我们现在可以使用print(s2.getvalue()) 10015 function calls in -0.020 seconds` Ordered by: cumulative time ncalls tottime percall cumtime percall filename:lineno(function) 0 0.000 0.000 profile:0(profiler) 1 0.000 0.000 0.000 0.000 :0(setprofile) 10011 -0.010 -0.000 -0.010 -0.000 <string>:1(<genexpr>) 1 -0.010 -0.010 -0.020 -0.020 <string>:1(<module>) 1 -0.000 -0.000 -0.020 -0.020 :0(exec) 1 -0.000 -0.000 -0.020 -0.020 profile:0(list(x for x in range(int(10*10*10*10/10*10+10))))
,这将输出以下(sane)报告: 至于为什么我们的自定义计时器函数会给出合理的结果,而pr2=profile.profile(timenow,0.000001)
与datetime.now().timestamp()
不匹配,首先必须注意的是profile
不提供timenow
datetime.now().timestamp()的计时。虽然它提供接近历元时间的时间,但它会少量关闭(不会影响正常剖面运行,因为在同一系统上,增量将相同)。
中使用的手动转换肯定不如timenow
datetime.now().timestamp()中的效率高。我只能推测后者效率太高,因此,
源代码无法正确测量 TL;博士profile
使用
,除非您有特定的理由不这样做。官方Python文档还声明建议使用的模块是cProfile
。虽然没有提供具体的理由,但文档似乎暗示,cProfile
可能表现得更好,适合大多数用户的目的(尽管它的语法略为详细)。您没有遗漏任何内容。一、 我们也发现了这种情况……并通过查看CPython源代码对其进行了验证。但是我不知道为什么会这样,只是事实上这就是写东西的方式。@martineau+1使用profile.profile()的正确方式是什么--Python3.7和3上也存在已验证的行为。8@jon:当前关于该方法的Python 3.x文档说它仅在cProfile
中可用,这意味着您必须使用cProfile
的profile.profile
方法之一。下面是一些.Yep,我发现在概要文件上使用inspect.getmembers()之后,出现了run()方法。我会用这些信息发布一个答案。@jon:FYI,当回复非OP所做的评论时,你需要添加前缀为run*()
的用户名,这样他们就会收到通知,你已经这样做了。我发现你在这种情况下完全是靠运气(因为有时我会回头看看,如果有的话,我最近自己做出的反应可能是什么)。@
>>> print(s1.getvalue()) 10013 function calls in 0.031 seconds Ordered by: cumulative time ncalls tottime percall cumtime percall filename:lineno(function) 10011 0.031 0.000 0.031 0.000 <stdin>:1(<genexpr>) 1 0.000 0.000 0.000 0.000 <stdin>:1(<module>) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}