在Python2.7和Python3.6中,我发现这是可行的:
from cProfile import Profile; p = Profile(); p.enable()...whereas这会引发一个异常:
from profile import Profile; p = Profile(); p.enable()
# --> AttributeError: 'Profile' object has no attribute 'enable'这让我感到惊讶,因为我认为(以及Python 3和Python 2状态的官方文档)这两个模块应该提供相同的程序员接口:
profile和cProfile模块都提供了以下功能: ..。class profile.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)..。enable()开始收集个人资料。
我遗漏了什么?使用profile.Profile()实例的正确方法是什么?
发布于 2021-02-07 04:12:41
在Python 3.8和更新的文档中,他们已经修正了这一点,以指定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:
# 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会将配置函数的输出推到stdout,而profile不会。filename:lineno(function)列的输出略有不同。cProfile通常会更容易地显示内置函数。- In the example I provided here, however, the passed in function is actually identifiable in `profile`'s output and _not_ in `cProfile`'s -- but if using a named function, it is identifiable in _both_ profilers' output (although the passed in _arguments_ to the function are only visible from `profile`'s output).cProfile和profile运行相同的函数,结果略有不同。似乎cProfile一般会生成两个更少的函数调用,并且会为相同的函数提供更有效的时间。timer和timeunit参数可以提供获得微秒精度相对于默认毫秒精度的好处。然而,试图使用这些方法似乎附带了一些注意事项:- `cProfile`'s timeunit function requires an integer, whereas `profile` expects a floating point number. This means you can't use `datetime.now().timestamp()` directly with `cProfile`, but must rather wrap it in a lambda to convert it to a full integer first.
- Additionally, for some reason `profile` seems to not work correctly with `datetime.now().timestamp()` even though that's in the format it's expecting. It will print out negative time values -- I show this below. Switching to the lambda form to convert it to integer doesn't help, as `profile` expects the floating point number.profile.Profile与datetime.now().timestamp()计时器的输出,用于提供微秒。
打印(s2.getvalue()) 10015函数调用in -0.020次`,顺序为:累积时间n调用全时每次调用和时间调用文件名:lineno(函数)0 0.000 0.000配置文件:0(分析器)1 0.000 0.000 0.000 :0(setprofile) 10011 -0.010 -0.000 -0.000 :1()1 -0.010 -0.010 -0.020 -0.020 :1() 1 -0.000 -0.000 -0.020 -0.020 :0(exec) 1 -0.000 -0.000 -0.020 -0.020 -0.020-0(x在范围内(int(10*10*10*10*10*10+10)datetime.now()来提供与datetime.now().timestamp()完全相同的输出格式),原因我无法解释。例如,如果我们定义:
def timenow():
now = datetime.now()
return (((now.year-1970) * 31557600) + (now.month * 2629800) +
(now.day * 86400) + (now.hour * 3600) + (now.minute * 60) +
now.second + (now.microsecond * 0.000001))我们现在可以使用pr2 = profile.Profile(timenow, 0.000001),它将输出以下(正常)报告:
>>> print(s2.getvalue())
10015 function calls in 0.041 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.006 0.006 0.041 0.041 profile:0(list(x for x in range(int(10*10*10*10/10*10+10))))
1 0.000 0.000 0.035 0.035 :0(exec)
1 0.017 0.017 0.035 0.035 <string>:1(<module>)
10011 0.018 0.000 0.018 0.000 <string>:1(<genexpr>)
1 0.001 0.001 0.001 0.001 :0(setprofile)
0 0.000 0.000 profile:0(profiler)与cProfile的输出(使用上面定义的自定义lambda计时器)相比,我们有:
>>> 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}至于为什么我们的自定义计时器函数给出了合理的结果,而datetime.now().timestamp()没有使用profile,首先必须注意的是,timenow没有为datetime.now().timestamp()提供时间。虽然它提供了接近时代的时间,但它的数量很小(不应该影响正常配置文件的运行,因为三角洲在同一个系统上是相同的)。timenow中使用的手动转换也肯定不如在datetime.now().timestamp()中使用的高效。我只能推测后者的效率太高,而且profile源代码在某种程度上没有进行适当的度量。
TL;DR
除非您有特定的理由不使用cProfile,否则使用它。官方的Python还指出,推荐的模块是cProfile。虽然没有提供具体的理由,但是文档似乎暗示cProfile可能表现得更好,适合大多数用户的使用(尽管它是一种稍微冗长的语法)。
https://stackoverflow.com/questions/52998945
复制相似问题