在Python中自动测试性能的正确方法(适合所有开发者)?
我们的Python应用程序(一个很酷的网络服务)有一整套测试(单元测试、集成测试等),所有开发者在提交代码之前都必须运行这些测试。
我想在测试套件中添加一些性能测试,以确保没有人添加会让我们运行得太慢的代码(对于“慢”的定义有点随意)。
显然,我可以把一些功能放到一个测试中,测量它的运行时间,然后和一些预设的标准进行比较。
这里有一些棘手的要求:
- 我希望每个开发者都能在自己的机器上测试代码(因为机器的CPU性能、操作系统(!Linux和一些Windows)和外部配置会有所不同 - Python版本、库和模块是一样的)。虽然测试服务器通常是个好主意,但并不能解决这个问题。
- 我希望测试是确定性的 - 无论在运行测试的机器上发生什么,我希望多次运行测试都能得到相同的结果。
我初步的想法:
- 使用timeit,每次运行测试时对系统进行基准测试。将性能测试的结果与基准进行比较。
- 使用cProfile来监控解释器,以忽略“外部噪音”。我不太确定我是否知道如何读取
pstats
结构,但我相信这是可以做到的。
还有其他想法吗?
谢谢!
Tal.
2 个回答
我希望测试是确定性的——无论在运行测试的机器上发生什么,我希望多次运行测试都能得到相同的结果。
失败。根据定义,这在一个有多个用户的多进程系统中几乎是不可能的。
要么重新考虑这个要求,要么找一个不涉及现代多进程操作系统的新环境来运行测试。
而且,你正在运行的网络应用程序本身就不是确定性的,所以强加某种“确定性”的性能测试并没有太大帮助。
当我们进行时间敏感的处理(比如雷达系统,那里“实时”真的意味着实时)时,我们并没有尝试进行确定性测试。我们进行了代码检查,并运行了一些简单的性能测试,主要是计算简单的平均值和最大值。
使用cProfile来监控解释器,以忽略“外部噪音”。我不太确定我是否知道如何读取pstats结构,但我相信这是可以做到的。
由分析器创建的Stats
对象就是你需要的。
http://docs.python.org/library/profile.html#the-stats-class
关注分析统计中的'pcalls',即原始调用次数,这样你就能得到一个大致确定性的结果。
看看这个 funkload,它可以帮你把单元测试变成功能测试或者负载测试,来评估你的网站表现得怎么样。
还有一个有趣的项目可以和funkload一起使用,那就是 codespeed。这个工具可以作为一个内部仪表盘,测量你每次提交代码时代码库的“速度”,并展示随时间变化的趋势图。这需要你有一些自动化的基准测试可以运行,但它可以帮助你准确记录性能的变化。到目前为止,我见过的codespeed最好的用法是 speed.pypy.org 网站。
关于你提到的确定性要求,也许最好的办法是利用统计数据?可以自动运行测试N次,计算所有运行结果的最小值、最大值、平均值和标准差?你可以看看这篇 关于基准测试的文章,里面有一些建议。