本期将总结几种获取程序运行时间的方法,极大的帮助对比不同算法/写法效率。
使用系统命令
每个操作系统都有自己的方法来算程序运行的时间,比如在Windows PowerShell中,可以用 Measure-Command 来看一个Python文件的运行时间:
Measure-Command {python tutorial.py}
在Ubuntu中,使用time命令:
time python tutorial.py
如果我们除了看整个 Python 脚本的运行时间外还想看看局部运行时间咋整?
使用 IPython 的 Magic Command
如果你使用过如Jupyter Notebook等工具会知道,他们用到了一个叫做 IPython 的交互式 Python 环境。
在 IPython 中,有一个特别方便的命令叫做 timeit。
对于某行代码的测量可以使用%timeit:
对于某一个代码单元格的测量,可以使用%%timeit:
使用timeit
如果不用IPython咋整,没关系,已经很厉害了,Python 有一个内置的timeit模块,可以帮助检测小段代码运行时间。
可以在命令行界面运行如下命令:
python -m timeit '[i for i in range(100)]'
使用 timeit 测量执行此列表推导式所需的时间,得到输出:
200000 loops, best of 5: 1.4 usec per loop
此输出表明每次计时将执行200000次列表推导,共计时测试了5次,最好的结果是1.4毫秒。
或者直接在Python中调用:
import timeit
print(timeit.timeit('[i for i in range(100)]', number=1))
对于更复杂的情况,有三个参数需要考虑:
- stmt:待测量的代码片段,默认是 pass
- setup:在运行 stmt 之前执行一些准备工作,默认也是 pass
- number:要运行 stmt 的次数
比如一个更复杂的例子:
import timeit
# prerequisites before running the stmt
my_setup = "from math import sqrt"
# code snippet we would like to measure
my_code = '''
def my_function():
for x in range(10000000):
sqrt(x)
'''
print(timeit.timeit(setup=my_setup,
stmt=my_code,
number=1000))
# 6.260000000000293e-05
使用time模块
Python中内置的time模块相信都不陌生,基本的用法是在待测代码段的起始与末尾分别打上时间戳,然后获得时间差:
import time
def my_function():
for i in range(10000000):
pass
start = time.perf_counter()
my_function()
print(time.perf_counter()-start)
# 0.1179838
我经常使用time.perf_counter()来获取时间,更精确,在之前的教程中有提过。
time模块中还有一些其他计时选择:
- time.timer():获取当前时间
- time.perf_counter():计算程序的执行时间(高分辨率)
- time.monotonic():计算程序的执行时间(低分辨率)
- time.process_time():计算某个进程的CPU时间
- time.thread_time():计算线程的CPU时间
假如我们需要在多个代码段测试运行时间,每个首尾都打上时间戳再计算时间差就有点繁琐了,咋整,上装饰器:
import time
def log_execution_time(func):
def wrapper(*args, **kwargs):
start = time.perf_counter()
res = func(*args, **kwargs)
end = time.perf_counter()
print(f'The execution of {func.__name__} used {end - start} seconds.')
return res
return wrapper
@log_execution_time
def my_function():
for i in range(10000000):
pass
my_function()
# The execution of my_function used 0.1156899 seconds.
如上例所示,这样就使得代码非常干净与整洁。