Section 194.1: 在 IPython 中使用 %%timeit 和 %timeit

分析字符串拼接的性能:

In [1]: import string
In [2]: %%timeit s=""; long_list=list(string.ascii_letters)*50
....: for substring in long_list:
....: s+=substring
....:
1000 loops, best of 3: 570 us per loop
In [3]: %%timeit long_list=list(string.ascii_letters)*50
....: s="".join(long_list)
....:
100000 loops, best of 3: 16.1 us per loop
Profiling loops over iterables and lists:
In [4]: %timeit for i in range(100000):pass
100 loops, best of 3: 2.82 ms per loop
In [5]: %timeit for i in list(range(100000)):pass
100 loops, best of 3: 3.95 ms per loop

分析对可迭代对象和列表的循环性能:

In [4]: %timeit for i in range(100000):pass
100 loops, best of 3: 2.82 ms per loop
In [5]: %timeit for i in list(range(100000)):pass
100 loops, best of 3: 3.95 ms per loop

Section 194.2: 使用 cProfile(推荐的性能分析器)

Python 包含一个名为 cProfile 的性能分析器。通常建议使用它而不是 timeit。

它会分析您脚本中的每个函数,并告诉您:

  • ncalls:函数被调用的次数
  • tottime:在给定函数中花费的总时间(不包括调用子函数的时间)
  • percall:每次调用的平均时间(tottime 除以 ncalls)
  • cumtime:在该函数及其所有子函数中花费的累积时间(从调用到退出)。即使是递归函数,这个数字也是准确的。
  • percall:cumtime 除以原始调用次数
  • filename:lineno(function):提供每个函数的相应数据

可以通过命令行轻松调用 cProfiler:

$ python -m cProfile main.py

按函数中花费的时间对返回的性能分析方法列表进行排序:

$ python -m cProfile -s time main.py

Section 194.3: timeit() 函数

分析数组中元素的重复性能:

>>> import timeit
>>> timeit.timeit('list(itertools.repeat("a", 100))', 'import itertools', number = 10000000)
10.997665435877963
>>> timeit.timeit('["a"]*100', number = 10000000)
7.118789926862576

Section 194.4: timeit 命令行

分析数字拼接的性能:

python -m timeit "'-'.join(str(n) for n in range(100))"
10000 loops, best of 3: 29.2 usec per loop

python -m timeit "'-'.join(map(str,range(100)))"
100000 loops, best of 3: 19.4 usec per loop

Section 194.5: 命令行中的 line_profiler

带有 @profile 指令的源代码,用于标记我们想要分析的函数:

import requests

@profile
def slow_func():
  s = requests.session()
  html=s.get("https://en.wikipedia.org/").text
  sum([pow(ord(x),3.1) for x in list(html)])

for i in range(50):
  slow_func()

使用 kernprof 命令逐行计算性能分析:

$ kernprof -lv so6.py

Wrote profile results to so6.py.lprof
Timer unit: 4.27654e-07 s

Total time: 22.6427 s
File: so6.py
Function: slow_func at line 4

Line # Hits Time Per Hit % Time Line Contents
==============================================================
4 @profile
5 def slow_func():
6 50 20729 414.6 0.0 s = requests.session()
7 50 47618627 952372.5 89.9 html=s.get("https://en.wikipedia.org/").text
8 50 5306958 106139.2 10.0 sum([pow(ord(x),3.1) for x in list(html)])

页面请求几乎总是比基于页面信息的任何计算都要慢。