【发布时间】:2014-02-12 00:53:08
【问题描述】:
我在一个文件中有一个 Python 脚本,它只需要 30 多秒即可运行。我正在尝试对其进行分析,因为我想大大减少这个时间。
我正在尝试使用 cProfile 分析脚本,但基本上它似乎告诉我的是,是的,主脚本需要很长时间才能运行,但并没有给出我期望的那种故障.在终端,我输入如下内容:
cat my_script_input.txt | python -m cProfile -s time my_script.py
我得到的结果是:
<my_script_output>
683121 function calls (682169 primitive calls) in 32.133 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
1 31.980 31.980 32.133 32.133 my_script.py:18(<module>)
121089 0.050 0.000 0.050 0.000 {method 'split' of 'str' objects}
121090 0.038 0.000 0.049 0.000 fileinput.py:243(next)
2 0.027 0.014 0.036 0.018 {method 'sort' of 'list' objects}
121089 0.009 0.000 0.009 0.000 {method 'strip' of 'str' objects}
201534 0.009 0.000 0.009 0.000 {method 'append' of 'list' objects}
100858 0.009 0.000 0.009 0.000 my_script.py:51(<lambda>)
952 0.008 0.000 0.008 0.000 {method 'readlines' of 'file' objects}
1904/952 0.003 0.000 0.011 0.000 fileinput.py:292(readline)
14412 0.001 0.000 0.001 0.000 {method 'add' of 'set' objects}
182 0.000 0.000 0.000 0.000 {method 'join' of 'str' objects}
1 0.000 0.000 0.000 0.000 fileinput.py:80(<module>)
1 0.000 0.000 0.000 0.000 fileinput.py:197(__init__)
1 0.000 0.000 0.000 0.000 fileinput.py:266(nextfile)
1 0.000 0.000 0.000 0.000 {isinstance}
1 0.000 0.000 0.000 0.000 fileinput.py:91(input)
1 0.000 0.000 0.000 0.000 fileinput.py:184(FileInput)
1 0.000 0.000 0.000 0.000 fileinput.py:240(__iter__)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
这似乎没有告诉我任何有用的信息。绝大多数时间只是简单地列出为:
ncalls tottime percall cumtime percall filename:lineno(function)
1 31.980 31.980 32.133 32.133 my_script.py:18(<module>)
在my_script.py中,第18行无非是文件头块注释的结束""",所以并不是说全部工作量都集中在第18行。整个脚本大部分是制作的主要是一些字符串拆分、排序和设置工作的基于行的处理,所以我期待找到大部分时间用于这些活动中的一项或多项。就目前而言,将 cProfile 结果中分组的所有时间都视为出现在注释行上没有任何意义,或者至少不能说明实际上一直在消耗什么。
编辑:我已经构建了一个与上述案例类似的最小工作示例来演示相同的行为:
mwe.py
import fileinput
for line in fileinput.input():
for i in range(10):
y = int(line.strip()) + int(line.strip())
然后调用它:
perl -e 'for(1..1000000){print "$_\n"}' | python -m cProfile -s time mwe.py
要得到结果:
22002536 function calls (22001694 primitive calls) in 9.433 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
1 8.004 8.004 9.433 9.433 mwe.py:1(<module>)
20000000 1.021 0.000 1.021 0.000 {method 'strip' of 'str' objects}
1000001 0.270 0.000 0.301 0.000 fileinput.py:243(next)
1000000 0.107 0.000 0.107 0.000 {range}
842 0.024 0.000 0.024 0.000 {method 'readlines' of 'file' objects}
1684/842 0.007 0.000 0.032 0.000 fileinput.py:292(readline)
1 0.000 0.000 0.000 0.000 fileinput.py:80(<module>)
1 0.000 0.000 0.000 0.000 fileinput.py:91(input)
1 0.000 0.000 0.000 0.000 fileinput.py:197(__init__)
1 0.000 0.000 0.000 0.000 fileinput.py:184(FileInput)
1 0.000 0.000 0.000 0.000 fileinput.py:266(nextfile)
1 0.000 0.000 0.000 0.000 {isinstance}
1 0.000 0.000 0.000 0.000 fileinput.py:240(__iter__)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
我是否以某种方式错误地使用了 cProfile?
【问题讨论】:
-
你能告诉我们你的剧本吗?或者,更好的是stripped-down version that still exhibits the same odd profile behavior?
-
另外,您的
my_script.pyc是否可能已过期但不知何故其时间戳比my_script.py晚?如果发生这种情况,您最终可能会从 .pyc 中实际运行(和分析)代码,但所有行号都已过期。 -
最后一件事,作为一个疯狂的猜测:你是在某处做一个
f.readlines()然后循环遍历结果吗? -
最后一件事:有时,您无法让 cProfile 在外部工作,但您可以在内部使用它,例如,如this example 所示。
-
@abarnert 我在问题中添加了一个最小示例。