我有一个负责一个长期运行任务的 Python 脚本。这个脚本同其他三个系统通信 – 它从系统 #1 和 #2 读取数据,合并它们然后再把它们推送到系统 #3。这是下面的描述。问题是迁移运行在我不满意的一个地方。因为我想知道该脚本的大部分工作是在与哪个慢的外部系统进行通信。Python 有一个非常好用的内建的分析器来回答这类问题。按照这篇文章来学习如何使用它。
分析器(Profiler)
基础用法非常简单。假设你有一个 myscript.py
。使用 profiler
运行它,你需要做的是:
1 2 |
$ python -m cProfile -o profile.out myscript.py <other-args> |
它将运行这个脚本并且 dump 这个 debug 数据到 profile.out。你也可以省略 -o profile.out
来让统计的 dumped 到脚本最后的 stdout。
Subprocesses
如果你的脚本使用了任何 subprocesses,事情就会变得有点复杂。以我来说,我对脚本的主流程不感兴趣 – 它所做的所有事情就是派生(spawn)一些 worker 子进程。我感兴趣的是在 worker 中发生了什么。
让我们假设你的代码与此类似:
1 2 3 4 5 6 7 8 9 10 11 12 |
import multiprocessing import time def worker(num): time.sleep(3) print 'Worker:', num if __name__ == '__main__': for i in range(5): p = multiprocessing.Process(target=worker, args=(i,)) p.start() |
你需要引入另外一个间接层:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import multiprocessing import cProfile import time def worker(num): time.sleep(3) print 'Worker:', num def profile_worker(num): cProfile.runctx('test(num)', globals(), locals(), 'profile-%d.out' %num) if __name__ == '__main__': for i in range(5): p = multiprocessing.Process(target=profile_worker, args=(i,)) p.start() |
就是这样。这个脚本运行之后,你将得到 profile-0.out
到 profile-4.out
这4个文件。
读取分析数据
如果你忽略 -o profile.out
这时将在 stdout 得到统计数据。这不是一个完美的解决方案。更好的解决方案是把数据 dump 到文件中然后使用 runsnake 来分析它。为了在 ubuntu 上安装它,你需要 wxpython 包,然后你才可以使用 easy-install
安装它。
1 2 3 |
$ sudo apt-get install python-wxgtk2.8 python-wxtools wx2.8-doc wx2.8-examples wx2.8-headers wx2.8-i18n $ sudo easy-install SquareMap RunSnakeRun |
由于某种原因我没有在 virtualenv 中运行工作。我需要一个全系统的 easy-install。有人抱怨缺失了 wx
模块。我的系统是 ubuntu 12.04。
然后,就很简单了:
1 2 |
$ runsnake profile.out |
你在不同的函数获得了很好的统计分析,调用次数和累计时间。这些数据可以告诉你关于你 app 的很多东西。以我而言我获悉了与其中一个系统通信花费了 90% 的时间。从那里开始我可以优化它。
来源