优化:通用原则和性能分析技术
立即解锁
发布时间: 2025-08-18 00:44:33 阅读量: 1 订阅数: 4 

# 优化:通用原则和性能分析技术
## 1. 性能分析工具与方法
### 1.1 可视化工具 KcacheGrind
KcacheGrind 是一个很棒的可视化工具,可用于展示性能分析数据。详情可查看:[KcacheGrind 官网](http://kcachegrind.sourceforge.net/cgi-bin/show.cgi)。
### 1.2 宏观和微观性能分析
- **宏观性能分析**:是检测有问题的函数(或至少其附近函数)的好方法。当找到可能有问题的函数后,就可以转向微观性能分析。
- **微观性能分析**:当找到运行缓慢的函数后,有时需要对程序的一部分进行更细致的性能分析。可以通过手动对代码的一部分进行速度测试来实现。例如,使用 `cProfile` 模块的装饰器:
```python
import tempfile, os, cProfile, pstats
def profile(column='time', list=5):
def _profile(function):
def __profile(*args, **kw):
s = tempfile.mktemp()
profiler = cProfile.Profile()
profiler.runcall(function, *args, **kw)
profiler.dump_stats(s)
p = pstats.Stats(s)
p.sort_stats(column).print_stats(list)
return __profile
return _profile
from myapp import main
@profile('time', 6)
def main_profiled():
return main()
main_profiled()
```
运行上述代码后,会输出性能分析结果,如下:
```plaintext
Fri Jun 20 00:30:36 2008 ...
1210 function calls in 10.129 CPU seconds
Ordered by: internal time
List reduced from 8 to 6 due to restriction <6>
ncalls tottime cumtime percall filename:lineno(function)
602 10.118 10.118 0.017 {time.sleep}
2 0.005 10.129 5.065 myapp.py:9(heavy)
400 0.004 4.080 0.010 myapp.py:3(lighter)
200 0.002 2.044 0.010 myapp.py:6(light)
1 0.000 10.129 10.129 myapp.py:16(main)
3 0.000 0.000 0.000 {range}
```
这种方法可以测试应用程序的部分功能,并使统计输出更加精确。
### 1.3 使用 `timeit` 测量代码片段执行时间
`timeit` 提供了一种简单的方法来测量小代码片段的执行时间,使用主机系统提供的最佳底层计时器(`time.time` 或 `time.clock`):
```python
from myapp import light
import timeit
t = timeit.Timer('main()')
t.timeit(number=5)
```
运行结果可能如下:
```plaintext
10000000 loops, best of 3: 0.0269 usec per loop
10000000 loops, best of 3: 0.0268 usec per loop
10000000 loops, best of 3: 0.0269 usec per loop
10000000 loops, best of 3: 0.0268 usec per loop
10000000 loops, best of 3: 0.0269 usec per loop
5.6196951866149902
```
这个模块允许重复调用代码,适合测试孤立的代码片段。不过在现有应用程序中使用不太方便。由于确定性分析器的结果会受计算机当前运行状态影响,所以多次重复测试并取平均值能得到更准确的结果。此外,一些计算机的特殊 CPU 功能(如 SpeedStep)可能会影响测试结果,因此持续重复测试小代码片段是个好做法。同时,还需考虑各种缓存(如 DNS 缓存或 CPU 缓存)的影响。
### 1.4 自定义装饰器测量代码执行时间
可以创建一个类似的装饰器来测量应用程序部分代码的执行时间:
```python
import time
import sys
if sys.platform == 'win32':
timer = time.clock
else:
timer = time.time
stats = {}
def duration(name='stats', stats=stats):
def _duration(function):
def __duration(*args, **kw):
start_time = timer()
try:
return function(*args, **kw)
finally:
stats[name] = timer() - start_time
return __duration
return _duration
from myapp import heavy
heavy = duration('this_func_is')(heavy)
heavy()
print(stats['this_func_is'])
```
使用这个装饰器可以在不影响应用程序的前提下,对应用程序代码进行内联性能分析。例如:
```python
stats = {}
from myapp import light
import myapp
myapp.light = duration('myapp.light')(myapp.light)
myapp.main()
print(stats)
```
## 2. 皮斯通(Pystones)测量
### 2.1 皮斯通测量的意义
在测量执行时间时,结果会依赖于计算机硬件。为了得到一个通用的测量标准,最简单的方法是对一组固定代码的执行速度进行基准测试,并计算出一个比率。这样,函数的执行时间就可以转换为一个通用的值,便于在任何计算机上进行比较。
### 2.2 相关工具和计算方法
Python 在其 `test` 包中提供了一个基准测试工具,用于测量一系列精心选择的操作的持续时间。结果是计算机每秒能够执行的皮斯通数量,以及执行基准测试所花费的时间(在现代硬件上通常约为 1 秒):
```python
from test import pystone
benchtime, pystones = pystone.pystones()
```
可以使用以下函数将执行时间转换为千皮斯通数:
```python
def seconds_to_kpystones(seconds):
return (pystones * seconds) / 1000
print(seconds_to_kpystones(0.03))
print(seconds_to_kpystones(1))
print(seconds_to_kpystones(2))
```
可以将这个转换函数集成到 `duration` 装饰器中,以得到以皮斯通为单位的值:
```python
def duration(name='stats', stats=stats):
def _duration(function):
def __duration(*args, **kw):
start_time = timer()
try:
return function(*args, **kw)
finally:
total = timer() - start_time
kstones = seconds_to_kpystones(total)
stats[name] = total, kstones
return __duration
return _duration
@duration()
def some_code():
time.sleep(0.5)
s
```
0
0
复制全文
相关推荐










