提交 776a1baa 编写于 作者: W wizardforcel

ex18

上级 9fe880f9
# 练习 18:性能测量
在本练习中,您将学习使用多种工具来分析您创建的数据结构和算法的性能。为了使这个介绍专注并且简洁,我们将查看练习 16 中的`sorted.py`算法的性能,然后在视频中,我会分析我们迄今为止所做的所有数据结构的性能。
> 原文:[Exercise 18: Measuring Performance](https://learncodethehardway.org/more-python-book/ex18.html)
> 译者:[飞龙](https://github.com/wizardforcel)
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
> 自豪地采用[谷歌翻译](https://translate.google.cn/)
在本练习中,你将学习使用多种工具来分析你创建的数据结构和算法的性能。为了使这个介绍专注并且简洁,我们将查看练习 16 中的`sorted.py`算法的性能,然后在视频中,我会分析我们迄今为止所做的所有数据结构的性能。
性能分析和调优是我最喜欢的计算机编程活动之一。在看电视的时候,我是那个手里拿着一团缠着的绳子的人,并且只打算把它解开,直到它很好并且有序。我喜欢探究复杂的奥秘,代码性能是最复杂的奥秘之一。有一些很好的并且实用的工具,用于分析代码的性能,使之比调试更好。
......@@ -17,7 +25,7 @@
### `timeit`
`timeit`模块不是非常有用。它所做的就是接受字符串形式的 Python 代码,并使用一些时间运行它。不能传递函数引用,`.py`文件或除字符串之外的任何内容。我们可以在`test_sorting.py`的结尾,测试`test_bubble_sort`函数需要多长时间:
`timeit`模块不是非常有用。它所做的就是接受字符串形式的 Python 代码,并使用一些时间运行它。不能传递函数引用,`.py`文件或除字符串之外的任何内容。我们可以在`test_sorting.py`的结尾,测试`test_bubble_sort`函数需要多长时间:
```py
if __name__ == '__main__':
......@@ -37,7 +45,7 @@ if __name__ == '__main__':
test_merge_sort()
```
并将`max_numbers`更改为大约 800,或足够大的数字,以便可以测量效果。一旦你完成了,然后在你的代码上运行`cProfile`
并将`max_numbers`更改为大约 800,或足够大的数字,以便可以测量效果。一旦你完成了,然后在你的代码上运行`cProfile`
```
$ python -m cProfile -s cumtime test_sorting.py | grep sorting.py
......@@ -96,5 +104,45 @@ $ python -m cProfile -s cumtime test_sorting.py | grep sorting.py
现在让我们查看,`dllist.py`如何影响其性能:
同样,我已经添加了标题,以便您可以看到发生了什么。在这种情况下,您可以看到,与`merge``merge_node``count`函数相比,`dllist.py`函数不会影响性能。这是很重要的,因为大多数程序员将运行优化`DoubleLinkedList`数据结构,但在`merge_sort`实现中可以获得更大的收益,并且完全可以避免使用`bubble_sort`。始终以最小的努力获得最大的改进。
同样,我已经添加了标题,以便你可以看到发生了什么。在这种情况下,你可以看到,与`merge``merge_node``count`函数相比,`dllist.py`函数不会影响性能。这是很重要的,因为大多数程序员将运行优化`DoubleLinkedList`数据结构,但在`merge_sort`实现中可以获得更大的收益,并且完全可以避免使用`bubble_sort`。始终以最小的努力获得最大的改进。
## 性能分析
分析性能只是一件事情,找出什么较慢,然后试图确定为什么它较慢。它类似于调试,除了你最好不要改变代码的行为。完成后,代码的工作方式应该完全一样,仅仅是更快执行。有时修复性能也会发现错误,但是当你尝试加速时,最好不要尝试完全重新设计。一次只做一件事。
在开始分析性能之前,另一件重要的事情是,软件所需的一些指标。通常快即是好,但没有目标,你最终会提出一些完全不必要的解决方案。如果你的系统以 50 个请求/秒执行,并且你真的只需要 100 个请求/秒,那么没有必要使用 Haskell 完全重写它,来获得 200 的性能。这个过程完全关于,“节省最多的钱,并且付出最少的努力”,并且你需要某种测量作为目标。
你可以从运营人员那里获得大部分测量结果,并且应该有很好的图表,显示了 CPU 使用情况,请求/秒,帧速率,任何他们或客户认为重要的东西。然后,你可以与他们一起设计测试,证明一些缓慢的东西需要定位,以便你可以改进代码来达到所需的目标。你可以从系统中榨取更多的性能,从而节省资金。你可以尝试并得出结论,这只是一个需要更多 CPU 资源的难题。有了一个作为目标的指标,你会明白什么时候放弃,或已经做得足够了。
你可以用于分析的最简单过程是这样:
+ 在代码上运行性能分析器,就像我在这里使用测试所做的一样。你得到的信息越多越好。有关免费的其他工具,请参阅深入学习部分。向人们询问一些工具,它们用于分析系统的速度。
+ 识别最慢和最小的代码段。不要编写一个巨大的函数,并尝试分析它。很多时候这些函数很慢,因为它们使用了一大堆其他很慢的函数。首先找到最慢和最小的函数,你最有可能得到最大的收益,并付出最少的努力。
+ 审查这些缓慢的代码,和任何他们接触的代码,寻找代码缓慢的可能原因。循环内有循环吗?调用函数太频繁吗?在调查诸如缓存之类的复杂技术之前,寻找可以改变的简单事物。
+ 一旦你列出了所有最慢和最小的函数,以及简单的更改,使它们更快并寻找规律。你能在其它你看不到的地方做这件事吗?
+ 最后,如果没有简单更改你可以更改的小函数,可以寻求可能的较大改进。也许真的是完全重写的时候了吗?不要这样做,直到你至少尝试了简单的修复。
+ 列出你尝试的所有东西,以及你所完成的所有性能增益。如果你不这样做,那么你会不断地回到你已经处理过的函数上,并浪费精力。
在这个过程中,“最慢和最小”的概念是变化的。你修复了十几个 10 行的函数并使其更快,这意味着现在你可以查看最慢的 100 行的函数。一旦你让 100 行的函数运行得更快,你可以查看正在运行的更大的一组函数,并提出使其加速的策略。
最后,加速的最好办法是完全不做。如果你正在对相同条件进行多重检查,请找到避免多次检查的方法。如果你反复计算数据库中的同一列,请执行一次。如果你在密集的循环中调用函数,但数据不怎么改变,请缓存它或者事先计算出来。在许多情况下,你可以通过简单地事先计算一些东西,并一次性存储它们,来用空间换时间。
在下一个练习中,我们将会使用这个过程,来改进这些算法的性能。
## 挑战练习
此练习的挑战是,将我对`bubble_sort``merge_sort`所做的所有操作,都应用到目前为止所创建的所有数据结构和算法。我不期望你改进他们,但只是在开发测试来显示性能问题时,记下笔记并分析性能。抵制现在修改任何东西的诱惑,因为我们将在练习 19 中提高性能。
## 研究性学习
+ 到目前为止,对所有代码运行这些分析工具,并分析性能。
+ 将结果与算法和数据结构的理论结果进行比较。
## 破坏它
尝试编写使数据结构崩溃的病态测试。你可能需要为他们提供大量数据,但使用性能分析的信息来确保正确。
## 深入学习
+ 查看`line_profiler`,它是另一个性能测量工具。它的优点是,你只能衡量你关心的函数,但缺点是你必须更改源代码。
+ `pyprof2calltree``KCacheGrind`是更先进的工具,但老实说只能在 Linux 上工作。在视频中,我演示在 Linux 下使用它们。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册