赵走x博客
网站访问量:151577
首页
书籍
软件
工具
古诗词
搜索
登录
Python性能分析与优化:8、line_profiler
Python性能分析与优化:7、性能分析示例
Python性能分析与优化:6、性能分析器:cProfile
Python性能分析与优化:5、性能分析最佳实践
Python性能分析与优化:4、运行时间复杂度
Python性能分析与优化:3、内存消耗和内存泄漏、过早优化的风险
Python性能分析与优化:2、性能分析可以分析什么
Python性能分析与优化:6、性能分析器:cProfile
资源编号:75726
书籍
Python性能分析与优化
热度:101
上一章介绍了性能分析的基础知识,展示了性能分析的重要性。如果把性能分析方法整合到开发过程中,就可以帮助我们提高产品的开发质量。另外,上一章还介绍了一些性能分析的具体方法。
# **性能分析器** 上一章介绍了性能分析的基础知识,展示了性能分析的重要性。如果把性能分析方法整合到开发过程中,就可以帮助我们提高产品的开发质量。另外,上一章还介绍了一些性能分析的具体方法。 上一章在最后介绍了程序运行时间复杂度的相关理论。在这一章,我们将会用到第一部分(关于性能分析的内容)。之后,我们将通过两个Python性能分析器(`cProfile`和`line_profiler`),把学到的理论付诸实践。 本章将介绍以下内容: * 性能分析器的基本信息 * 性能分析器的下载和安装方法 * 通过示例演示性能分析器的功能 * 比较两种性能分析器的差异 ## **2.1 认识新朋友:性能分析器** 学完上一章所有的理论和简单示例之后,我们应该看看真正的Python了。我们先来看看目前最受关注也是用户最多的两个Python性能分析器:`cProfile`和`line_profiler`。两者将通过不同的方式帮助我们分析代码的性能。 `cProfile`([https://docs.python.org/2/library/profile.html#module-cProfile](https://docs.python.org/2/library/profile.html#module-cProfile))从Python 2.5开始就是该语言默认的性能分析器,官方推荐在绝大多数场景中使用。而`line_profiler`([https://github.com/rkern/line_profiler](https://github.com/rkern/line_profiler))虽然不是Python官方发布的性能分析器,但是也被广泛使用。 下面详细地介绍两种性能分析器的相关知识。 ## **2.2 `cProfile`** 就像之前提到的,`cProfile`自Python 2.5以来就是标准版Python解释器默认的性能分析器。它是一种确定性的性能分析器,提供了一组API帮助开发者收集Python程序运行的信息,更确切地说,是统计每个函数消耗的CPU时间。同时它还提供了其他细节,比如函数被调用的次数。 `cProfile`只测量CPU时间,并不关心内存消耗和其他与内存相关的信息统计。尽管如此,它是代码优化过程中一个很不错的起点,因为大多数时候,这个分析工具都会快速地为我们提供一组优化方案。 `cProfile`不需要安装,因为它是语言自带的一部分。要使用它,直接导入`cProfile`包即可。 > 确定性的性能分析器其实就是基于事件的性能分析器的另一种说法(更多细节请参考上一章内容)。也就是说,这个性能分析器会关注代码运行过程中的函数调用、返回语句等事件,甚至可以测量程序运行期间发生的每一个事件(与我们在上一章看到的统计式性能分析器不同)。 下面是从Python文档里提取出来的一个非常简单的例子: ``` import cProfile import re cProfile.run('re.compile("foo|bar")') ``` 上面代码的输出结果如下: ``` 214 function calls (207 primitive calls) in 0.000 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.000 0.000
:1(
) 2 0.000 0.000 0.000 0.000 enum.py:284(__call__) 2 0.000 0.000 0.000 0.000 enum.py:526(__new__) 1 0.000 0.000 0.000 0.000 enum.py:836(__and__) 1 0.000 0.000 0.000 0.000 re.py:232(compile) 1 0.000 0.000 0.000 0.000 re.py:271(_compile) 1 0.000 0.000 0.000 0.000 sre_compile.py:249(_compile_charset) 1 0.000 0.000 0.000 0.000 sre_compile.py:276(_optimize_charset) 2 0.000 0.000 0.000 0.000 sre_compile.py:453(_get_iscased) 1 0.000 0.000 0.000 0.000 sre_compile.py:461(_get_literal_prefix) 1 0.000 0.000 0.000 0.000 sre_compile.py:492(_get_charset_prefix) 1 0.000 0.000 0.000 0.000 sre_compile.py:536(_compile_info) 2 0.000 0.000 0.000 0.000 sre_compile.py:595(isstring) 1 0.000 0.000 0.000 0.000 sre_compile.py:598(_code) 3/1 0.000 0.000 0.000 0.000 sre_compile.py:71(_compile) 1 0.000 0.000 0.000 0.000 sre_compile.py:759(compile) 3 0.000 0.000 0.000 0.000 sre_parse.py:111(__init__) 7 0.000 0.000 0.000 0.000 sre_parse.py:160(__len__) 18 0.000 0.000 0.000 0.000 sre_parse.py:164(__getitem__) 7 0.000 0.000 0.000 0.000 sre_parse.py:172(append) 3/1 0.000 0.000 0.000 0.000 sre_parse.py:174(getwidth) 1 0.000 0.000 0.000 0.000 sre_parse.py:224(__init__) 8 0.000 0.000 0.000 0.000 sre_parse.py:233(__next) 2 0.000 0.000 0.000 0.000 sre_parse.py:249(match) 6 0.000 0.000 0.000 0.000 sre_parse.py:254(get) 1 0.000 0.000 0.000 0.000 sre_parse.py:286(tell) 1 0.000 0.000 0.000 0.000 sre_parse.py:417(_parse_sub) 2 0.000 0.000 0.000 0.000 sre_parse.py:475(_parse) 1 0.000 0.000 0.000 0.000 sre_parse.py:76(__init__) 2 0.000 0.000 0.000 0.000 sre_parse.py:81(groups) 1 0.000 0.000 0.000 0.000 sre_parse.py:903(fix_flags) 1 0.000 0.000 0.000 0.000 sre_parse.py:919(parse) 1 0.000 0.000 0.000 0.000 {built-in method _sre.compile} 1 0.000 0.000 0.000 0.000 {built-in method builtins.exec} 25 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance} 29/26 0.000 0.000 0.000 0.000 {built-in method builtins.len} 2 0.000 0.000 0.000 0.000 {built-in method builtins.max} 9 0.000 0.000 0.000 0.000 {built-in method builtins.min} 6 0.000 0.000 0.000 0.000 {built-in method builtins.ord} 48 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 5 0.000 0.000 0.000 0.000 {method 'find' of 'bytearray' objects} 1 0.000 0.000 0.000 0.000 {method 'items' of 'dict' objects} ``` 从这个结果中可以收集到如下信息。 * 第一行告诉我们一共有214个函数调用被监控,其中207个是原生(primitive)调用,表明这些调用不涉及递归。 * `ncalls`表示函数调用的次数。如果在这一列中有两个数值,就表示有递归调用。第二个数值是原生调用的次数,第一个数值是总调用次数。这个数值可以帮助识别潜在的bug(当数值大得异乎寻常时可能就是bug),或者可能需要进行内联函数扩展(inline expansion)的位置。 * `tottime`是函数内部消耗的总时间(不包括调用其他函数的时间)。这列信息可以帮助开发者找到可以进行优化的、运行时间较长的循环。 * `percall`是`tottime`除以`ncalls`,表示一个函数每次调用的平均消耗时间。 * `cumtime`是之前所有子函数消耗时间的累计和(也包含递归调用时间)。这个数值可以帮助开发者从整体视角识别性能问题,比如算法选择错误。 * 另一个`percall`是用`cumtime`除以原生调用的数量,表示到该函数调用时,每个原生调用的平均消耗时间。 * `filename:lineno(function)`显示了被分析函数所在的文件名、行号、函数名。 ### **2.2.1 工具的局限** 不存在透明的性能分析器。也就是说,即使像`cProfile`这样消耗极小的性能分析器,仍然会对代码实际的性能造成影响。当一个事件被触发时,事件实际发生的时间相比性能分析器查询到的系统内部时钟的时间,还是会有一些延迟。另外,当程序计数器离开性能分析器代码,回到用户代码中继续执行时,程序也会出现滞后。 除了这些之外,作为计算机内部的任何一段代码,内部时钟都有一个精度范围,任何小于这个精度的测量值都会被忽略。也就是说,如果进行性能分析的代码含有许多递归调用,或者一个函数需要调用许多函数,开发者就应该对这个函数做特殊处理,因为测量误差不断地累计最终会变得非常显著。 ### **2.2.2 支持的API** `cProfile`性能分析器提供了一些方法,帮助开发者收集程序中不同类型上下文的性能统计信息: ``` run(command, filename=None, sort=-1) ``` 上面这个经典的方法,在前面的例子中使用过,用来收集命令执行的性能统计信息。当命令被调用时,会执行下面这个函数: ``` exec(command, __main__.__dict__, __main__.__dict__) ``` 如果没有设置文件名`filename`,它就会创建一个新的`stats`类的实例(后面会详细介绍这个类)。下面的代码和之前的例子相同,但是带着新参数: ``` import cProfile import re cProfile.run('re.compile("foo|bar")', 'stats', 'cumtime') ``` 如果你运行这段代码,就会发现没有结果输出。但是,如果你检查文件夹里的内容,会发现一个新文件,叫stats。打开文件,你会发现里面的内容无法理解,因为文件是使用二进制格式保存的。后面将介绍如何读取文件信息并通过它来创建我们自己的报告: ``` runctx(command, globals, locals, filename=None) ``` 这个方法和之前的很相似。唯一不同的是,它的参数列表中支持两个字典参数:`globals`和`locals`。当它被调用之后,会执行如下函数: ``` exec(command, globals, locals) ``` 它会和`run`一样收集性能分析的统计信息。让我们用下面的例子来看看`run`和`runctx`之间的主要差别。 首先让我们用`run`函数,写出的代码如下: ``` import cProfile def runRe(): import re cProfile.run('re.compile("foo|bar")') runRe() ``` 当我们运行代码时,会得到下面的错误信息: ``` Traceback (most recent call last): File "cprof-test1.py", line 7, in
runRe() ... File "/usr/lib/python2.7/cProfile.py", line 140, in runctx exec cmd in globals, locals File "
", line 1, in
NameError: name 're' is not defined ``` `re`模块没有被`run`方法发现,因为就像我们在前面见到的,`run`调用的`exec`函数的参数是`__main__.__dict__`。 现在,再让我们用`runctx`方法: ``` import cProfile def runRe(): import re cProfile.runctx('re.compile("foo|bar")', None, locals()) runRe() ``` 它会输出下面的有效结果: ``` 214 function calls (207 primitive calls) in 0.000 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.000 0.000
:1(
) 2 0.000 0.000 0.000 0.000 enum.py:284(__call__) 2 0.000 0.000 0.000 0.000 enum.py:526(__new__) 1 0.000 0.000 0.000 0.000 enum.py:836(__and__) 1 0.000 0.000 0.000 0.000 re.py:232(compile) 1 0.000 0.000 0.000 0.000 re.py:271(_compile) 1 0.000 0.000 0.000 0.000 sre_compile.py:249(_compile_charset) 1 0.000 0.000 0.000 0.000 sre_compile.py:276(_optimize_charset) 2 0.000 0.000 0.000 0.000 sre_compile.py:453(_get_iscased) 1 0.000 0.000 0.000 0.000 sre_compile.py:461(_get_literal_prefix) 1 0.000 0.000 0.000 0.000 sre_compile.py:492(_get_charset_prefix) 1 0.000 0.000 0.000 0.000 sre_compile.py:536(_compile_info) 2 0.000 0.000 0.000 0.000 sre_compile.py:595(isstring) 1 0.000 0.000 0.000 0.000 sre_compile.py:598(_code) 3/1 0.000 0.000 0.000 0.000 sre_compile.py:71(_compile) 1 0.000 0.000 0.000 0.000 sre_compile.py:759(compile) 3 0.000 0.000 0.000 0.000 sre_parse.py:111(__init__) 7 0.000 0.000 0.000 0.000 sre_parse.py:160(__len__) 18 0.000 0.000 0.000 0.000 sre_parse.py:164(__getitem__) 7 0.000 0.000 0.000 0.000 sre_parse.py:172(append) 3/1 0.000 0.000 0.000 0.000 sre_parse.py:174(getwidth) 1 0.000 0.000 0.000 0.000 sre_parse.py:224(__init__) 8 0.000 0.000 0.000 0.000 sre_parse.py:233(__next) 2 0.000 0.000 0.000 0.000 sre_parse.py:249(match) 6 0.000 0.000 0.000 0.000 sre_parse.py:254(get) 1 0.000 0.000 0.000 0.000 sre_parse.py:286(tell) 1 0.000 0.000 0.000 0.000 sre_parse.py:417(_parse_sub) 2 0.000 0.000 0.000 0.000 sre_parse.py:475(_parse) 1 0.000 0.000 0.000 0.000 sre_parse.py:76(__init__) 2 0.000 0.000 0.000 0.000 sre_parse.py:81(groups) 1 0.000 0.000 0.000 0.000 sre_parse.py:903(fix_flags) 1 0.000 0.000 0.000 0.000 sre_parse.py:919(parse) 1 0.000 0.000 0.000 0.000 {built-in method _sre.compile} 1 0.000 0.000 0.000 0.000 {built-in method builtins.exec} 25 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance} 29/26 0.000 0.000 0.000 0.000 {built-in method builtins.len} 2 0.000 0.000 0.000 0.000 {built-in method builtins.max} 9 0.000 0.000 0.000 0.000 {built-in method builtins.min} 6 0.000 0.000 0.000 0.000 {built-in method builtins.ord} 48 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 5 0.000 0.000 0.000 0.000 {method 'find' of 'bytearray' objects} 1 0.000 0.000 0.000 0.000 {method 'items' of 'dict' objects} ``` 在性能分析过程中,`Profile(timer=None, timeunit=0.0, subcalls=True,builtins=True)`方法可以返回一个类,为开发者提供比`run`和`runctx`更多的控制。 `timer`参数是一个自定义函数,可以通过与默认函数不同的方式测量时间。它必须是一个可以返回当前时间数值的函数。如果开发者需要自定义函数,这个函数的消耗应该尽可能地低,避免测量口径造成的差异(请参考上一小节内容)。 如果`timer`的返回值是一个整数,那么`timeunit`参数就表示单位时间换算成秒的系数。例如,如果返回值单位时间是毫秒,那么`timeunit`应该就是`.001`。 让我们再看看`Profile`返回类的其他方法。 * `enable()`:表示开始收集性能分析数据。 * `disable()`:表示停止收集性能分析数据。 * `create_stats()`:表示停止收集数据,并为已收集的数据创建`stats`对象。 * `print_stats(sort=-1)`:创建一个`stats`对象,打印分析结果。 * `dump_stats(filename)`:把当前性能分析的内容写进一个文件。 * `run(cmd)`:和之前介绍过的`run`函数相同。 * `runctx(cmd, globals, locals)`:和之前介绍过的`runctx`函数相同。 * `runcall(func, *args, **kwargs)`:收集被调用函数`func`的性能分析信息。 让我们用下面的方式演示前面的例子: ``` import cProfile def runRe(): import re re.compile("foo|bar") prof = cProfile.Profile() prof.enable() runRe() prof.create_stats() prof.print_stats() ``` 在上面的性能分析代码中行数变多了,但这样做其实可以减少对原代码的干扰。通过这种方式对已经写好的代码或者已经通过测试的代码进行性能分析时,可以直接增加或删除性能分析代码,不需要调整源代码。 还有一种方式对源代码干扰更少,不需要增加任何代码,但是运行脚本时需要用一些命令行参数: ``` $ python -m cProfile your_script.py -o your_script.profile ``` 需要注意的是,这样做会分析全部代码的性能,因此当你只想分析部分代码的性能时,这个方法可能无法返回想要的结果。 在介绍更详细、更有趣的例子之前,让我们再看看`Stats`类能为我们做什么。 ### **2.2.3 `Stats`类** `pstats`模块为开发者提供了Stats类,可以读取和操作`stats`文件(用之前介绍过的一种方法,把性能分析内容保存为二进制文件)的内容。 例如,下面的代码可以加载stats文件,打印里面经过排序的内容: ``` import pstats p = pstats.Stats('stats') p.strip_dirs().sort_stats(-1).print_stats() ``` > 注意`Stats`类的构造器可以接收`cProfile.Profile`类型的参数,可以不用文件名称作为数据源。 让我们更仔细地看看`pstats.Stats`类提供的方法。 * `strip_dirs()`:删除报告中所有函数文件名的路径信息。这个方法会改变`stats`实例内部的顺序,任何运行该方法的实例都将随机排列项目(每一行信息)的顺序。如果两个项目被认为是相同的(函数名相同,文件名相同,行数相同),那么这两个项目就可以合并。 * `add(*filenames)`:这个方法将文件名对应的文件的信息加载到当前的`stats`对象中。需要注意的是,和前面单独一个文件的处理方式相同,引用同一函数的`stats`项目(`filename:lineno(function)`,即文件名、行数和函数名)将被合并。 * `dump_stats(filename)`:就像`cProfile.Profile`类,这个方法把加载到`Stats`类的数据保存为一个文件。 * `sort_stats(*keys)`:这个方法从Python 2.3就开始出现,它是通过一系列条件依次对所有项目进行排序,从而调整`stats`对象的。当条件不止一个时,只有经过前一个条件排序后是相同的项目,才使用后一个条件进行排序。例如,如果`sort_stats ('name', 'file')`条件被使用,那么首先会把所有项目按照函数名排序,然后对名称相同的项目再按照文件名排序。 这个方法有时会自作聪明,遇到缩略词有歧义时就会自动按照拟定的规则进行理解,所以使用的时候要当心。目前支持排序的条件如下表所示。 | 准则 | 含义| 升序/降序排列| | --- | --- | --- | | `calls` | 调用总次数| 降序 | | `cumulative`| 累计时间 | 降序| |`cumtime`| 累计时间| 降序 | | `file`| 文件名 | 升序 | | `filename` | 文件名| 升序| | `module`| 模块名| 升序 | | `ncalls`| 调用总次数| 降序 | | `pcalls` | 原始调用数| 降序| | `line`| 行号| 升序| | `name`| 函数名| 升序 | | `nfl`| 函数名/文件名/行号组合| 降序 | | `stdname`| 标准名称 | 升序| | `time`| 函数内部运行时间| 降序| | `tottime`| 函数内部运行时间 | 降序| > **`nfl`与`stdname`** > > 这两种排序方式的差异在于,`stdname`按照字符串打印的方式排序,就是把数字也作为字符串(4, 20, 30排序后就是20, 30, 4),而`nfl`是把行号字段作为数字进行排序。 最后,为了保持程序的兼容性,一些数字可以替换表格中的参数。`-1`、`0`、`1`、`2`分别表示`stdname`、`calls`、`time`、`cumulative`。 * `reverse_order()`:这个方法会逆反原来参数的排序方法(因此,如果原来按升序排列,现在就会变成降序)。 * `print_stats(*restrictions)`:这个方法是把信息打印到`STDOUT`。里面的可选参数用于体现打印结果的形式,可以是整数、小数和字符串。解释如下。 * 整数:限制打印的行数。 * 0.0到1.0(包含)之间的小数:表示按总行数的百分比打印。 * 字符串:正则表达式,用于匹配`stdname`。  上图显示的结果是从以下代码中调用`print_stats`输出的: ``` import cProfile import pstats def runRe(): import re re.compile("foo|bar") prof = cProfile.Profile() prof.enable() runRe() prof.create_stats() p = pstats.Stats(prof) # 打印满足正则表达式的前10行结果 p.print_stats(10, 1.0, '.*.py.*') ``` 如果函数里有多个参数,就依次满足各个参数。就像我们在上面那段代码里看到的,性能分析器的结果可能会非常长。但是,如果排序合理,就可以用参数汇总输出结果,获取需要的数据。 `print_callers(*restrictions)`方法的输入参数和使用规则与前面的函数相同,但是输出结果有一点儿不同。它会显示程序执行过程中调用的每个函数的调用次数、总时间和累计时间,以及文件名、行号和函数名的组合。 让我们通过下面的例子,看看如何通过`cProfile.Profile`和`Stats`获取程序调用函数列表: ``` import cProfile import pstats def runRe(): import re re.compile("foo|bar") prof = cProfile.Profile() prof.enable() runRe() prof.create_stats() p = pstats.Stats(prof) p.print_callers() ``` 注意观察这里是如何把`profile.Stats`和`cProfile.Profile`组合起来使用的。它们会同时运行并共同显示我们想要的结果。现在,让我们看看输出结果: ``` Function was called by... ncalls tottime cumtime {method 'find' of 'bytearray' objects} <- 5 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:276(_optimize_charset) {method 'append' of 'list' objects} <- 22 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:71(_compile) 5 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:249(_compile_charset) 4 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:276(_optimize_charset) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:492(_get_charset_prefix) 5 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:536(_compile_info) 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:598(_code) 7 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:172(append) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:417(_parse_sub) {method 'items' of 'dict' objects} <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:759(compile) {built-in method builtins.isinstance} <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/enum.py:836(__and__) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/re.py:271(_compile) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:595(isstring) 18 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:164(__getitem__) 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:224(__init__) 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:903(fix_flags) {built-in method builtins.len} <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/re.py:271(_compile) 8 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:71(_compile) 4 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:276(_optimize_charset) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:536(_compile_info) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:81(groups) 7 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:160(__len__) 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:286(tell) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:417(_parse_sub) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:475(_parse) {built-in method builtins.max} <- 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:174(getwidth) {built-in method builtins.min} <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:536(_compile_info) 8 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:174(getwidth) {built-in method builtins.ord} <- 6 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:475(_parse) {built-in method _sre.compile} <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:759(compile) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/re.py:232(compile) <- 1 0.000 0.000 /Volumes/UP/python-profile/6-8.py:4(runRe) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/re.py:271(_compile) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/re.py:232(compile) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/enum.py:284(__call__) <- 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/enum.py:836(__and__) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/enum.py:526(__new__) <- 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/enum.py:284(__call__) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:71(_compile) <- 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:71(_compile) 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:598(_code) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:249(_compile_charset) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:536(_compile_info) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/enum.py:836(__and__) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/re.py:271(_compile) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:276(_optimize_charset) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:536(_compile_info) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:453(_get_iscased) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:461(_get_literal_prefix) 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:492(_get_charset_prefix) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:461(_get_literal_prefix) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:536(_compile_info) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:492(_get_charset_prefix) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:536(_compile_info) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:536(_compile_info) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:598(_code) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:595(isstring) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/re.py:271(_compile) 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:759(compile) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:598(_code) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:759(compile) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:759(compile) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/re.py:271(_compile) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:76(__init__) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:919(parse) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:81(groups) <- 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:759(compile) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:111(__init__) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:417(_parse_sub) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:475(_parse) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:160(__len__) <- 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:492(_get_charset_prefix) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:417(_parse_sub) 3 0.000 0.000 {built-in method builtins.len} /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:164(__getitem__) <- 8 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:71(_compile) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:492(_get_charset_prefix) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:417(_parse_sub) 6 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:475(_parse) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:172(append) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:417(_parse_sub) 6 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:475(_parse) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:174(getwidth) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:536(_compile_info) 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:174(getwidth) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:224(__init__) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:919(parse) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:233(__next) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:224(__init__) 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:249(match) 6 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:254(get) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:249(match) <- 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:417(_parse_sub) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:254(get) <- 6 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:475(_parse) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:286(tell) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:417(_parse_sub) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:417(_parse_sub) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:919(parse) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:475(_parse) <- 2 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:417(_parse_sub) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:903(fix_flags) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:919(parse) /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_parse.py:919(parse) <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/sre_compile.py:759(compile) /Volumes/UP/python-profile/6-8.py:4(runRe) <- /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/cProfile.py:50(create_stats) <- {method 'disable' of '_lsprof.Profiler' objects} <- 1 0.000 0.000 /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/cProfile.py:50(create_stats) ``` `print_callees(*restrictions)`方法打印一列调用其他函数的函数。其数据显示格式和限制参数与上一个函数相同。 这个结果表示右边的函数是被左边的函数调用的。