在上一篇文章中,我提到过 cProfile 对 Python 进行调优,但是仅仅只是简单的一笔带过,这篇文章就针对这个内容,单独扩展一下。cProfile 是 Python 的性能测试工具,另外一个同类工具是 python 实现的 profile,不过 cProfile 是 C 语言扩展的实现。
官方文档页面:http://docs.python.org/2/library/profile.html#module-cProfile。
先从一个例子开始:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
def delay():
time.sleep(10)
def main():
delay()
print "123"
if __name__ == '__main__':
main()
使用下面这个命令就可以快速诊断:
python -m cProfile profile_run.py
输出如下:
5 function calls in 10.002 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.002 0.002 10.002 10.002 profile_run.py:11(main)
1 0.000 0.000 10.002 10.002 profile_run.py:4(<module>)
1 0.000 0.000 10.000 10.000 profile_run.py:7(delay) <-- 调用者这里
1 0.000 0.000 0.000 0.000 {method'disable'of'_lsprof.Profiler'objects}
1 10.000 10.000 10.000 10.000 {time.sleep} <--- 元凶在这里
如果想输出到文件,添加一个 - o 参数即可:
python -m cProfile -o profile_output profile_run.py
若想按照某列排序,则可以添加这个参数:
python -m cProfile -o profile_output -s tottime profile_run.py
那么等等,这个结果文件如何识别呢:
ncalls: 这个函数被调用的次数
tottime:函数的具体执行时间,不包含其他函数消耗的时间
percall:每次调用的消耗(包含其他函数消耗和不包含的时间)
cumtime:程序消耗的总时间
然后看一个实际的成果看一下结果如何,具体的诊断数据:
发现最慢的执行模块是 not_operation 这个函数:
def not_operation(operand, dictionary, pfile):
"""Performs the operation `NOT operand`."""
# A list of all the documents (sorted)
all_docs = dictionary.all_docs()
# A list of the documents matching `operand` (sorted)
results = get_results(operand, dictionary, pfile, force_list=True)
return [doc for doc in all_docs if doc not in results]
接下来是怎么修复了:
# the fix.
def not_operation(operand, dictionary, pfile):
"""Performs the operation `NOT operand`."""
# A list of all the documents (sorted)
all_docs = dictionary.all_docs()
# A list of the documents matching `operand` (sorted)
results = get_results(operand, dictionary, pfile, force_list=True)
return list_a_and_not_list_b(all_docs, results)
def list_a_and_not_list_b(a, b):
"""Returns `a AND NOT b`.
Both a and b are expected to be sorted lists.
"""results = []
idx_a = 0
idx_b = 0
while idx_a <len(a) and idx_b <len(b):
if a[idx_a] <b[idx_b]:
results.append(a[idx_a])
idx_a += 1
elif b[idx_b] <a[idx_a]:
idx_b += 1
else:
idx_a += 1
idx_b += 1
while idx_a <len(a):
results.append(a[idx_a])
idx_a += 1
对了,说起来,上面图片查看工具是 cprofilev,是针对 cProfile 的查看工具,使用命令安装:
pip install bottle cprofilev
cprofilev profile_output
如果在 Windows 安装默认有点问题,你如果想解决,可以自己看一下:)