mirror of
https://github.com/fofolee/uTools-Manuals.git
synced 2025-06-08 15:04:05 +08:00
63 lines
63 KiB
HTML
63 lines
63 KiB
HTML
<div class="body" role="main"><div class="section" id="the-python-profilers"><h1><span class="yiyi-st" id="yiyi-10">27.4. </span><span class="yiyi-st" id="yiyi-11">The Python Profilers</span></h1><p><span class="yiyi-st" id="yiyi-12"><strong>源代码:</strong> <a class="reference external" href="https://hg.python.org/cpython/file/3.5/Lib/profile.py">Lib / profile.py</a>和<a class="reference external" href="https://hg.python.org/cpython/file/3.5/Lib/pstats.py">Lib / pstats.py</a></span></p><div class="section" id="introduction-to-the-profilers"><h2><span class="yiyi-st" id="yiyi-13">27.4.1. </span><span class="yiyi-st" id="yiyi-14">Introduction to the profilers</span></h2><p id="index-0"><span class="yiyi-st" id="yiyi-15"><a class="reference internal" href="#module-cProfile" title="cProfile"><code class="xref py py-mod docutils literal"><span class="pre">cProfile</span></code></a>和<a class="reference internal" href="#module-profile" title="profile: Python source profiler."><code class="xref py py-mod docutils literal"><span class="pre">profile</span></code></a>提供<em class="dfn">确定性分析</em>的Python程序。</span><span class="yiyi-st" id="yiyi-16"><em class="dfn">配置文件</em>是一组统计信息,描述程序的各个部分执行的频率和时间。</span><span class="yiyi-st" id="yiyi-17">这些统计信息可通过<a class="reference internal" href="#module-pstats" title="pstats: Statistics object for use with the profiler."><code class="xref py py-mod docutils literal"><span class="pre">pstats</span></code></a>模块格式化为报告。</span></p><p><span class="yiyi-st" id="yiyi-18">Python标准库提供了同一个性能分析界面的两种不同的实现:</span></p><ol class="arabic simple"><li><span class="yiyi-st" id="yiyi-19"><a class="reference internal" href="#module-cProfile" title="cProfile"><code class="xref py py-mod docutils literal"><span class="pre">cProfile</span></code></a>建议大多数用户;它是一个C扩展,具有合理的开销,使其适合于分析长期运行的程序。</span><span class="yiyi-st" id="yiyi-20">基于由Brett Rosen和Ted Czotter贡献的<code class="xref py py-mod docutils literal"><span class="pre">lsprof</span></code>。</span></li><li><span class="yiyi-st" id="yiyi-21"><a class="reference internal" href="#module-profile" title="profile: Python source profiler."><code class="xref py py-mod docutils literal"><span class="pre">profile</span></code></a>,这是一个纯Python模块,其接口由<a class="reference internal" href="#module-cProfile" title="cProfile"><code class="xref py py-mod docutils literal"><span class="pre">cProfile</span></code></a>模拟,但会对分析的程序增加显着的开销。</span><span class="yiyi-st" id="yiyi-22">如果你试图以某种方式扩展profiler,这个模块的任务可能会更容易。</span><span class="yiyi-st" id="yiyi-23">最初由吉姆·罗斯金德设计和写作。</span></li></ol><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-24">注意</span></p><p class="last"><span class="yiyi-st" id="yiyi-25">分析器模块被设计为为给定程序提供执行配置文件,而不是用于基准测试目的(对于合理准确的结果,有<a class="reference internal" href="timeit.html#module-timeit" title="timeit: Measure the execution time of small code snippets."><code class="xref py py-mod docutils literal"><span class="pre">timeit</span></code></a>)。</span><span class="yiyi-st" id="yiyi-26">这特别适用于针对C代码的基准化Python代码:分析器引入了Python代码的开销,但不是C级函数,因此C代码看起来比任何Python代码都快。</span></p></div></div><div class="section" id="instant-user-s-manual"><h2><span class="yiyi-st" id="yiyi-27">27.4.2. </span><span class="yiyi-st" id="yiyi-28">Instant User’s Manual</span></h2><p><span class="yiyi-st" id="yiyi-29">本部分提供给“不想阅读手册”的用户。它提供了一个非常简短的概述,并允许用户在现有应用程序上快速执行概要分析。</span></p><p><span class="yiyi-st" id="yiyi-30">要对包含单个参数的函数进行概要分析,您可以执行以下操作:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">cProfile</span>
|
||
<span class="kn">import</span> <span class="nn">re</span>
|
||
<span class="n">cProfile</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s1">'re.compile("foo|bar")'</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-31">(如果后者在您的系统上不可用,请使用<a class="reference internal" href="#module-profile" title="profile: Python source profiler."><code class="xref py py-mod docutils literal"><span class="pre">profile</span></code></a>而不是<a class="reference internal" href="#module-cProfile" title="cProfile"><code class="xref py py-mod docutils literal"><span class="pre">cProfile</span></code></a>。</span></p><p><span class="yiyi-st" id="yiyi-32">上述操作将运行<a class="reference internal" href="re.html#re.compile" title="re.compile"><code class="xref py py-func docutils literal"><span class="pre">re.compile()</span></code></a>,并打印如下所示的配置文件结果:</span></p><pre><code class="language-python"><span></span> <span class="mi">197</span> <span class="n">function</span> <span class="n">calls</span> <span class="p">(</span><span class="mi">192</span> <span class="n">primitive</span> <span class="n">calls</span><span class="p">)</span> <span class="ow">in</span> <span class="mf">0.002</span> <span class="n">seconds</span>
|
||
|
||
<span class="n">Ordered</span> <span class="n">by</span><span class="p">:</span> <span class="n">standard</span> <span class="n">name</span>
|
||
|
||
<span class="n">ncalls</span> <span class="n">tottime</span> <span class="n">percall</span> <span class="n">cumtime</span> <span class="n">percall</span> <span class="n">filename</span><span class="p">:</span><span class="n">lineno</span><span class="p">(</span><span class="n">function</span><span class="p">)</span>
|
||
<span class="mi">1</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.001</span> <span class="mf">0.001</span> <span class="o"><</span><span class="n">string</span><span class="o">></span><span class="p">:</span><span class="mi">1</span><span class="p">(</span><span class="o"><</span><span class="n">module</span><span class="o">></span><span class="p">)</span>
|
||
<span class="mi">1</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.001</span> <span class="mf">0.001</span> <span class="n">re</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">212</span><span class="p">(</span><span class="nb">compile</span><span class="p">)</span>
|
||
<span class="mi">1</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.001</span> <span class="mf">0.001</span> <span class="n">re</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">268</span><span class="p">(</span><span class="n">_compile</span><span class="p">)</span>
|
||
<span class="mi">1</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="n">sre_compile</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">172</span><span class="p">(</span><span class="n">_compile_charset</span><span class="p">)</span>
|
||
<span class="mi">1</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="n">sre_compile</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">201</span><span class="p">(</span><span class="n">_optimize_charset</span><span class="p">)</span>
|
||
<span class="mi">4</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="n">sre_compile</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">25</span><span class="p">(</span><span class="n">_identityfunction</span><span class="p">)</span>
|
||
<span class="mi">3</span><span class="o">/</span><span class="mi">1</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="mf">0.000</span> <span class="n">sre_compile</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">33</span><span class="p">(</span><span class="n">_compile</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-33">第一行表示监控了197个呼叫。</span><span class="yiyi-st" id="yiyi-34">在这些调用中,192个<em class="dfn">原语</em>,意味着调用不是通过递归诱发的。</span><span class="yiyi-st" id="yiyi-35">下一行:<code class="docutils literal"><span class="pre">已订购</span> <span class="pre">:</span> <span class="pre">标准</span> <span class="pre">name</span></code>在最右边的列用于排序输出。</span><span class="yiyi-st" id="yiyi-36">列标题包括:</span></p><dl class="docutils"><dt><span class="yiyi-st" id="yiyi-37">ncalls</span></dt><dd><span class="yiyi-st" id="yiyi-38">对于呼叫数,</span></dd><dt><span class="yiyi-st" id="yiyi-39">tt</span></dt><dd><span class="yiyi-st" id="yiyi-40">在给定函数中花费的总时间(并且不包括调用子函数的时间)</span></dd><dt><span class="yiyi-st" id="yiyi-41">percall</span></dt><dd><span class="yiyi-st" id="yiyi-42">是<code class="docutils literal"><span class="pre">tottime</span></code>除以<code class="docutils literal"><span class="pre">ncalls</span></code>的商</span></dd><dt><span class="yiyi-st" id="yiyi-43">cumtime</span></dt><dd><span class="yiyi-st" id="yiyi-44">是在此和所有子函数中花费的累积时间(从调用到退出)。</span><span class="yiyi-st" id="yiyi-45">此图对于递归函数是精确的<em>even</em>。</span></dd><dt><span class="yiyi-st" id="yiyi-46">percall</span></dt><dd><span class="yiyi-st" id="yiyi-47">是<code class="docutils literal"><span class="pre">cumtime</span></code>除以原始调用的商</span></dd><dt><span class="yiyi-st" id="yiyi-48">filename:lineno(function)</span></dt><dd><span class="yiyi-st" id="yiyi-49">提供每个功能的相应数据</span></dd></dl><p><span class="yiyi-st" id="yiyi-50">当第一列中有两个数字(例如<code class="docutils literal"><span class="pre">3/1</span></code>)时,表示函数递归。</span><span class="yiyi-st" id="yiyi-51">第二个值是原始调用的数量,前者是调用的总数。</span><span class="yiyi-st" id="yiyi-52">注意,当函数不递归时,这两个值是相同的,并且只打印单个图形。</span></p><p><span class="yiyi-st" id="yiyi-53">您可以通过为<code class="xref py py-func docutils literal"><span class="pre">run()</span></code>函数指定文件名,而不是在配置文件运行结束时打印输出,而是将结果保存到文件中:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">cProfile</span>
|
||
<span class="kn">import</span> <span class="nn">re</span>
|
||
<span class="n">cProfile</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="s1">'re.compile("foo|bar")'</span><span class="p">,</span> <span class="s1">'restats'</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-54"><a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">pstats.Stats</span></code></a>类从文件中读取配置文件结果,并以各种方式格式化它们。</span></p><p><span class="yiyi-st" id="yiyi-55">文件<a class="reference internal" href="#module-cProfile" title="cProfile"><code class="xref py py-mod docutils literal"><span class="pre">cProfile</span></code></a>也可以作为脚本调用来配置其他脚本。</span><span class="yiyi-st" id="yiyi-56">例如:</span></p><pre><code class="language-python"><span></span><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">cProfile</span> <span class="p">[</span><span class="o">-</span><span class="n">o</span> <span class="n">output_file</span><span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="n">s</span> <span class="n">sort_order</span><span class="p">]</span> <span class="n">myscript</span><span class="o">.</span><span class="n">py</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-57"><code class="docutils literal"><span class="pre">-o</span></code>将配置文件结果写入文件,而不是标准输出</span></p><p><span class="yiyi-st" id="yiyi-58"><code class="docutils literal"><span class="pre">-s</span></code>指定<a class="reference internal" href="#pstats.Stats.sort_stats" title="pstats.Stats.sort_stats"><code class="xref py py-func docutils literal"><span class="pre">sort_stats()</span></code></a>排序值之一,以对输出进行排序。</span><span class="yiyi-st" id="yiyi-59">这仅适用于未提供<code class="docutils literal"><span class="pre">-o</span></code>的情况。</span></p><p><span class="yiyi-st" id="yiyi-60"><a class="reference internal" href="#module-pstats" title="pstats: Statistics object for use with the profiler."><code class="xref py py-mod docutils literal"><span class="pre">pstats</span></code></a>模块的<a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>类有多种方法用于操作和打印保存到配置文件结果文件中的数据:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">pstats</span>
|
||
<span class="n">p</span> <span class="o">=</span> <span class="n">pstats</span><span class="o">.</span><span class="n">Stats</span><span class="p">(</span><span class="s1">'restats'</span><span class="p">)</span>
|
||
<span class="n">p</span><span class="o">.</span><span class="n">strip_dirs</span><span class="p">()</span><span class="o">.</span><span class="n">sort_stats</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">print_stats</span><span class="p">()</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-61"><a class="reference internal" href="#pstats.Stats.strip_dirs" title="pstats.Stats.strip_dirs"><code class="xref py py-meth docutils literal"><span class="pre">strip_dirs()</span></code></a>方法从所有模块名称中删除了无关的路径。</span><span class="yiyi-st" id="yiyi-62"><a class="reference internal" href="#pstats.Stats.sort_stats" title="pstats.Stats.sort_stats"><code class="xref py py-meth docutils literal"><span class="pre">sort_stats()</span></code></a>方法根据打印的标准模块/行/名称字符串对所有条目进行排序。</span><span class="yiyi-st" id="yiyi-63"><a class="reference internal" href="#pstats.Stats.print_stats" title="pstats.Stats.print_stats"><code class="xref py py-meth docutils literal"><span class="pre">print_stats()</span></code></a>方法打印出所有统计信息。</span><span class="yiyi-st" id="yiyi-64">您可以尝试以下排序调用:</span></p><pre><code class="language-python"><span></span><span class="n">p</span><span class="o">.</span><span class="n">sort_stats</span><span class="p">(</span><span class="s1">'name'</span><span class="p">)</span>
|
||
<span class="n">p</span><span class="o">.</span><span class="n">print_stats</span><span class="p">()</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-65">第一个调用实际上会按照函数名对列表排序,第二个调用将打印出统计数据。</span><span class="yiyi-st" id="yiyi-66">以下是一些有趣的试验呼吁:</span></p><pre><code class="language-python"><span></span><span class="n">p</span><span class="o">.</span><span class="n">sort_stats</span><span class="p">(</span><span class="s1">'cumulative'</span><span class="p">)</span><span class="o">.</span><span class="n">print_stats</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-67">这会按照函数中的累积时间对配置文件进行排序,然后只打印十个最重要的行。</span><span class="yiyi-st" id="yiyi-68">如果你想了解什么算法需要时间,上面的行是你会使用。</span></p><p><span class="yiyi-st" id="yiyi-69">如果你想看看什么功能循环很多,并花了很多时间,你会做:</span></p><pre><code class="language-python"><span></span><span class="n">p</span><span class="o">.</span><span class="n">sort_stats</span><span class="p">(</span><span class="s1">'time'</span><span class="p">)</span><span class="o">.</span><span class="n">print_stats</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-70">根据每个函数中花费的时间排序,然后打印前十个函数的统计信息。</span></p><p><span class="yiyi-st" id="yiyi-71">您也可以尝试:</span></p><pre><code class="language-python"><span></span><span class="n">p</span><span class="o">.</span><span class="n">sort_stats</span><span class="p">(</span><span class="s1">'file'</span><span class="p">)</span><span class="o">.</span><span class="n">print_stats</span><span class="p">(</span><span class="s1">'__init__'</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-72">这将按照文件名对所有统计信息进行排序,然后只打印类init方法的统计信息(因为它们在其中用<code class="docutils literal"><span class="pre">__init__</span></code>拼写而成)。</span><span class="yiyi-st" id="yiyi-73">作为最后一个例子,你可以尝试:</span></p><pre><code class="language-python"><span></span><span class="n">p</span><span class="o">.</span><span class="n">sort_stats</span><span class="p">(</span><span class="s1">'time'</span><span class="p">,</span> <span class="s1">'cumulative'</span><span class="p">)</span><span class="o">.</span><span class="n">print_stats</span><span class="p">(</span><span class="o">.</span><span class="mi">5</span><span class="p">,</span> <span class="s1">'init'</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-74">此行使用时间的主键和累积时间的辅助键排序统计信息,然后打印出一些统计信息。</span><span class="yiyi-st" id="yiyi-75">具体来说,首先将列表剔除到其原始大小的50%(re:<code class="docutils literal"><span class="pre">.5</span></code>),然后只保留包含<code class="docutils literal"><span class="pre">init</span></code>的行,子列表。</span></p><p><span class="yiyi-st" id="yiyi-76">如果你想知道什么函数调用上面的函数,你现在可以(<code class="docutils literal"><span class="pre">p</span></code>仍然根据最后的标准排序)do:</span></p><pre><code class="language-python"><span></span><span class="n">p</span><span class="o">.</span><span class="n">print_callers</span><span class="p">(</span><span class="o">.</span><span class="mi">5</span><span class="p">,</span> <span class="s1">'init'</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-77">并且您将获得每个列出的函数的调用者列表。</span></p><p><span class="yiyi-st" id="yiyi-78">如果你想要更多的功能,你将必须阅读手册,或猜测以下功能:</span></p><pre><code class="language-python"><span></span><span class="n">p</span><span class="o">.</span><span class="n">print_callees</span><span class="p">()</span>
|
||
<span class="n">p</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s1">'restats'</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-79">作为脚本调用,<a class="reference internal" href="#module-pstats" title="pstats: Statistics object for use with the profiler."><code class="xref py py-mod docutils literal"><span class="pre">pstats</span></code></a>模块是一个用于读取和检查概要文件转储的统计浏览器。</span><span class="yiyi-st" id="yiyi-80">它有一个简单的面向行的界面(使用<a class="reference internal" href="cmd.html#module-cmd" title="cmd: Build line-oriented command interpreters."><code class="xref py py-mod docutils literal"><span class="pre">cmd</span></code></a>实现)和交互式帮助。</span></p></div><div class="section" id="module-cProfile"><h2><span class="yiyi-st" id="yiyi-81">27.4.3. <a class="reference internal" href="#module-profile" title="profile: Python source profiler."><code class="xref py py-mod docutils literal"><span class="pre">profile</span></code></a>和<a class="reference internal" href="#module-cProfile" title="cProfile"><code class="xref py py-mod docutils literal"><span class="pre">cProfile</span></code></a>模块参考</span></h2><p><span class="yiyi-st" id="yiyi-82"><a class="reference internal" href="#module-profile" title="profile: Python source profiler."><code class="xref py py-mod docutils literal"><span class="pre">profile</span></code></a>和<a class="reference internal" href="#module-cProfile" title="cProfile"><code class="xref py py-mod docutils literal"><span class="pre">cProfile</span></code></a>模块提供以下功能:</span></p><dl class="function"><dt id="profile.run"><span class="yiyi-st" id="yiyi-83"> <code class="descclassname">profile.</code><code class="descname">run</code><span class="sig-paren">(</span><em>command</em>, <em>filename=None</em>, <em>sort=-1</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-84">此函数接受可传递到<a class="reference internal" href="functions.html#exec" title="exec"><code class="xref py py-func docutils literal"><span class="pre">exec()</span></code></a>函数的单个参数,以及可选的文件名。</span><span class="yiyi-st" id="yiyi-85">在所有情况下,此例程执行:</span></p><pre><code class="language-python"><span></span><span class="n">exec</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">__main__</span><span class="o">.</span><span class="n">__dict__</span><span class="p">,</span> <span class="n">__main__</span><span class="o">.</span><span class="n">__dict__</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-86">并从执行中收集分析统计信息。</span><span class="yiyi-st" id="yiyi-87">如果没有文件名,则此函数自动创建<a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>实例并打印简单的性能分析报告。</span><span class="yiyi-st" id="yiyi-88">如果指定排序值,则会传递到此<a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>实例以控制结果的排序方式。</span></p></dd></dl><dl class="function"><dt id="profile.runctx"><span class="yiyi-st" id="yiyi-89"> <code class="descclassname">profile.</code><code class="descname">runctx</code><span class="sig-paren">(</span><em>command</em>, <em>globals</em>, <em>locals</em>, <em>filename=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-90">此函数类似于<a class="reference internal" href="#profile.run" title="profile.run"><code class="xref py py-func docutils literal"><span class="pre">run()</span></code></a>,添加了参数以提供<em>命令</em>字符串的全局和本地化字典。</span><span class="yiyi-st" id="yiyi-91">该例程执行:</span></p><pre><code class="language-python"><span></span><span class="n">exec</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="nb">globals</span><span class="p">,</span> <span class="nb">locals</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-92">并像上面的<a class="reference internal" href="#profile.run" title="profile.run"><code class="xref py py-func docutils literal"><span class="pre">run()</span></code></a>函数一样收集分析统计信息。</span></p></dd></dl><dl class="class"><dt id="profile.Profile"><span class="yiyi-st" id="yiyi-93"> <em class="property">class </em><code class="descclassname">profile.</code><code class="descname">Profile</code><span class="sig-paren">(</span><em>timer=None</em>, <em>timeunit=0.0</em>, <em>subcalls=True</em>, <em>builtins=True</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-94">这个类通常仅在需要比<code class="xref py py-func docutils literal"><span class="pre">cProfile.run()</span></code>函数提供的更精确的分析控制时才使用。</span></p><p><span class="yiyi-st" id="yiyi-95">可以提供自定义定时器,用于通过<em>timer</em>参数来测量运行代码所需的时间。</span><span class="yiyi-st" id="yiyi-96">这必须是返回表示当前时间的单个数字的函数。</span><span class="yiyi-st" id="yiyi-97">如果数字是整数,<em>timeunit</em>指定一个乘数,指定每个时间单位的持续时间。</span><span class="yiyi-st" id="yiyi-98">例如,如果定时器返回以千秒为单位测量的时间,则时间单位为<code class="docutils literal"><span class="pre">.001</span></code>。</span></p><p><span class="yiyi-st" id="yiyi-99">直接使用<a class="reference internal" href="#profile.Profile" title="profile.Profile"><code class="xref py py-class docutils literal"><span class="pre">Profile</span></code></a>类允许格式化配置文件结果,而无需将配置文件数据写入文件:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">cProfile</span><span class="o">,</span> <span class="nn">pstats</span><span class="o">,</span> <span class="nn">io</span>
|
||
<span class="n">pr</span> <span class="o">=</span> <span class="n">cProfile</span><span class="o">.</span><span class="n">Profile</span><span class="p">()</span>
|
||
<span class="n">pr</span><span class="o">.</span><span class="n">enable</span><span class="p">()</span>
|
||
<span class="c1"># ... do something ...</span>
|
||
<span class="n">pr</span><span class="o">.</span><span class="n">disable</span><span class="p">()</span>
|
||
<span class="n">s</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">StringIO</span><span class="p">()</span>
|
||
<span class="n">sortby</span> <span class="o">=</span> <span class="s1">'cumulative'</span>
|
||
<span class="n">ps</span> <span class="o">=</span> <span class="n">pstats</span><span class="o">.</span><span class="n">Stats</span><span class="p">(</span><span class="n">pr</span><span class="p">,</span> <span class="n">stream</span><span class="o">=</span><span class="n">s</span><span class="p">)</span><span class="o">.</span><span class="n">sort_stats</span><span class="p">(</span><span class="n">sortby</span><span class="p">)</span>
|
||
<span class="n">ps</span><span class="o">.</span><span class="n">print_stats</span><span class="p">()</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">getvalue</span><span class="p">())</span>
|
||
</code></pre><dl class="method"><dt id="profile.Profile.enable"><span class="yiyi-st" id="yiyi-100"> <code class="descname">enable</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-101">开始收集分析数据。</span></p></dd></dl><dl class="method"><dt id="profile.Profile.disable"><span class="yiyi-st" id="yiyi-102"> <code class="descname">disable</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-103">停止收集分析数据。</span></p></dd></dl><dl class="method"><dt id="profile.Profile.create_stats"><span class="yiyi-st" id="yiyi-104"> <code class="descname">create_stats</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-105">停止收集分析数据并将结果作为当前配置文件在内部记录。</span></p></dd></dl><dl class="method"><dt id="profile.Profile.print_stats"><span class="yiyi-st" id="yiyi-106"> <code class="descname">print_stats</code><span class="sig-paren">(</span><em>sort=-1</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-107">基于当前配置文件创建<a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>对象,并将结果打印到stdout。</span></p></dd></dl><dl class="method"><dt id="profile.Profile.dump_stats"><span class="yiyi-st" id="yiyi-108"> <code class="descname">dump_stats</code><span class="sig-paren">(</span><em>filename</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-109">将当前配置文件的结果写入<em>filename</em>。</span></p></dd></dl><dl class="method"><dt id="profile.Profile.run"><span class="yiyi-st" id="yiyi-110"> <code class="descname">run</code><span class="sig-paren">(</span><em>cmd</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-111">通过<a class="reference internal" href="functions.html#exec" title="exec"><code class="xref py py-func docutils literal"><span class="pre">exec()</span></code></a>配置cmd。</span></p></dd></dl><dl class="method"><dt id="profile.Profile.runctx"><span class="yiyi-st" id="yiyi-112"> <code class="descname">runctx</code><span class="sig-paren">(</span><em>cmd</em>, <em>globals</em>, <em>locals</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-113">使用指定的全局和本地环境通过<a class="reference internal" href="functions.html#exec" title="exec"><code class="xref py py-func docutils literal"><span class="pre">exec()</span></code></a>配置cmd。</span></p></dd></dl><dl class="method"><dt id="profile.Profile.runcall"><span class="yiyi-st" id="yiyi-114"> <code class="descname">runcall</code><span class="sig-paren">(</span><em>func</em>, <em>*args</em>, <em>**kwargs</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-115">个人资料<code class="docutils literal"><span class="pre">func(* args,</span> <span class="pre">** kwargs)</span></code></span></p></dd></dl></dd></dl></div><div class="section" id="the-stats-class"><h2><span class="yiyi-st" id="yiyi-116">27.4.4. </span><span class="yiyi-st" id="yiyi-117">The <code class="xref py py-class docutils literal"><span class="pre">Stats</span></code> Class</span></h2><p><span class="yiyi-st" id="yiyi-118">使用<a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>类对分析器数据进行分析。</span></p><dl class="class"><dt id="pstats.Stats"><span class="yiyi-st" id="yiyi-119"> <em class="property">class </em><code class="descclassname">pstats.</code><code class="descname">Stats</code><span class="sig-paren">(</span><em>*filenames or profile</em>, <em>stream=sys.stdout</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-120">此类构造函数从<em>filename</em>(或文件名列表)或从<code class="xref py py-class docutils literal"><span class="pre">Profile</span></code>实例创建“统计对象”的实例。</span><span class="yiyi-st" id="yiyi-121">输出将打印到<em>流</em>指定的流。</span></p><p><span class="yiyi-st" id="yiyi-122">由上述构造函数选择的文件必须由相应版本的<a class="reference internal" href="#module-profile" title="profile: Python source profiler."><code class="xref py py-mod docutils literal"><span class="pre">profile</span></code></a>或<a class="reference internal" href="#module-cProfile" title="cProfile"><code class="xref py py-mod docutils literal"><span class="pre">cProfile</span></code></a>创建。</span><span class="yiyi-st" id="yiyi-123">具体来说,在此分析器的未来版本中,保证了<em>无</em>文件兼容性,并且与其他分析器生成的文件没有兼容性。</span><span class="yiyi-st" id="yiyi-124">如果提供了几个文件,则将合并相同功能的所有统计信息,以便可以在单个报告中考虑多个进程的总体视图。</span><span class="yiyi-st" id="yiyi-125">如果附加文件需要与现有<a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>对象中的数据组合,则可以使用<a class="reference internal" href="#pstats.Stats.add" title="pstats.Stats.add"><code class="xref py py-meth docutils literal"><span class="pre">add()</span></code></a>方法。</span></p><p><span class="yiyi-st" id="yiyi-126">可以使用<code class="xref py py-class docutils literal"><span class="pre">cProfile.Profile</span></code>或<a class="reference internal" href="#profile.Profile" title="profile.Profile"><code class="xref py py-class docutils literal"><span class="pre">profile.Profile</span></code></a>对象作为配置文件数据源,而不是从文件读取配置文件数据。</span></p><p><span class="yiyi-st" id="yiyi-127"><a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>对象具有以下方法:</span></p><dl class="method"><dt id="pstats.Stats.strip_dirs"><span class="yiyi-st" id="yiyi-128"> <code class="descname">strip_dirs</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-129"><a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>类的此方法从文件名中删除所有前导路径信息。</span><span class="yiyi-st" id="yiyi-130">它在缩小打印输出的大小以适合(接近)80列非常有用。</span><span class="yiyi-st" id="yiyi-131">此方法修改对象,并且剥离的信息丢失。</span><span class="yiyi-st" id="yiyi-132">在执行条操作之后,对象被认为具有以“随机”顺序的条目,因为它恰好在对象初始化和加载之后。</span><span class="yiyi-st" id="yiyi-133">如果<a class="reference internal" href="#pstats.Stats.strip_dirs" title="pstats.Stats.strip_dirs"><code class="xref py py-meth docutils literal"><span class="pre">strip_dirs()</span></code></a>导致两个函数名不可区分(它们在同一文件名的同一行上,并具有相同的函数名),则这两个条目的统计信息将累积为一个条目。</span></p></dd></dl><dl class="method"><dt id="pstats.Stats.add"><span class="yiyi-st" id="yiyi-134"> <code class="descname">add</code><span class="sig-paren">(</span><em>*filenames</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-135"><a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>类的此方法会将其他概要分析信息累积到当前概要分析对象中。</span><span class="yiyi-st" id="yiyi-136">其参数应引用由相应版本的<a class="reference internal" href="#profile.run" title="profile.run"><code class="xref py py-func docutils literal"><span class="pre">profile.run()</span></code></a>或<code class="xref py py-func docutils literal"><span class="pre">cProfile.run()</span></code>创建的文件名。</span><span class="yiyi-st" id="yiyi-137">相同命名(re:file,line,name)函数的统计信息将自动累积到单个函数统计中。</span></p></dd></dl><dl class="method"><dt id="pstats.Stats.dump_stats"><span class="yiyi-st" id="yiyi-138"> <code class="descname">dump_stats</code><span class="sig-paren">(</span><em>filename</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-139">将加载到<a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>对象中的数据保存到名为<em>filename</em>的文件。</span><span class="yiyi-st" id="yiyi-140">如果文件不存在,则创建该文件,如果文件已经存在,则会被覆盖。</span><span class="yiyi-st" id="yiyi-141">这等效于<a class="reference internal" href="#profile.Profile" title="profile.Profile"><code class="xref py py-class docutils literal"><span class="pre">profile.Profile</span></code></a>和<code class="xref py py-class docutils literal"><span class="pre">cProfile.Profile</span></code>类中同名的方法。</span></p></dd></dl><dl class="method"><dt id="pstats.Stats.sort_stats"><span class="yiyi-st" id="yiyi-142"> <code class="descname">sort_stats</code><span class="sig-paren">(</span><em>*keys</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-143">This method modifies the <a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a> object by sorting it according to the supplied criteria. </span><span class="yiyi-st" id="yiyi-144">参数通常是标识排序基础的字符串(例如:<code class="docutils literal"><span class="pre">'time'</span></code>或<code class="docutils literal"><span class="pre">'name'</span></code>)。</span></p><p><span class="yiyi-st" id="yiyi-145">当提供多个键时,当在它们之前选择的所有键中存在相等时,附加键被用作次级标准。</span><span class="yiyi-st" id="yiyi-146">例如,<code class="docutils literal"><span class="pre">sort_stats('name',</span> <span class="pre">'file')</span></code>将根据函数名称对所有条目进行排序,相同的函数名)。</span></p><p><span class="yiyi-st" id="yiyi-147">缩写可用于任何键名称,只要缩写是明确的。</span><span class="yiyi-st" id="yiyi-148">以下是当前定义的键:</span></p><table border="1" class="docutils"><thead valign="bottom"><tr class="row-odd"><th class="head"><span class="yiyi-st" id="yiyi-149">有效Arg</span></th><th class="head"><span class="yiyi-st" id="yiyi-150">含义</span></th></tr></thead><tbody valign="top"><tr class="row-even"><td><span class="yiyi-st" id="yiyi-151"><code class="docutils literal"><span class="pre">'calls'</span></code></span></td><td><span class="yiyi-st" id="yiyi-152">呼叫计数</span></td></tr><tr class="row-odd"><td><span class="yiyi-st" id="yiyi-153"><code class="docutils literal"><span class="pre">'cumulative'</span></code></span></td><td><span class="yiyi-st" id="yiyi-154">累积时间</span></td></tr><tr class="row-even"><td><span class="yiyi-st" id="yiyi-155"><code class="docutils literal"><span class="pre">'cumtime'</span></code></span></td><td><span class="yiyi-st" id="yiyi-156">累积时间</span></td></tr><tr class="row-odd"><td><span class="yiyi-st" id="yiyi-157"><code class="docutils literal"><span class="pre">'file'</span></code></span></td><td><span class="yiyi-st" id="yiyi-158">文件名</span></td></tr><tr class="row-even"><td><span class="yiyi-st" id="yiyi-159"><code class="docutils literal"><span class="pre">'filename'</span></code></span></td><td><span class="yiyi-st" id="yiyi-160">文件名</span></td></tr><tr class="row-odd"><td><span class="yiyi-st" id="yiyi-161"><code class="docutils literal"><span class="pre">'module'</span></code></span></td><td><span class="yiyi-st" id="yiyi-162">文件名</span></td></tr><tr class="row-even"><td><span class="yiyi-st" id="yiyi-163"><code class="docutils literal"><span class="pre">'ncalls'</span></code></span></td><td><span class="yiyi-st" id="yiyi-164">呼叫计数</span></td></tr><tr class="row-odd"><td><span class="yiyi-st" id="yiyi-165"><code class="docutils literal"><span class="pre">'pcalls'</span></code></span></td><td><span class="yiyi-st" id="yiyi-166">原始调用计数</span></td></tr><tr class="row-even"><td><span class="yiyi-st" id="yiyi-167"><code class="docutils literal"><span class="pre">'line'</span></code></span></td><td><span class="yiyi-st" id="yiyi-168">电话号码</span></td></tr><tr class="row-odd"><td><span class="yiyi-st" id="yiyi-169"><code class="docutils literal"><span class="pre">'name'</span></code></span></td><td><span class="yiyi-st" id="yiyi-170">函数名</span></td></tr><tr class="row-even"><td><span class="yiyi-st" id="yiyi-171"><code class="docutils literal"><span class="pre">'nfl'</span></code></span></td><td><span class="yiyi-st" id="yiyi-172">名称/文件/行</span></td></tr><tr class="row-odd"><td><span class="yiyi-st" id="yiyi-173"><code class="docutils literal"><span class="pre">'stdname'</span></code></span></td><td><span class="yiyi-st" id="yiyi-174">标准名称</span></td></tr><tr class="row-even"><td><span class="yiyi-st" id="yiyi-175"><code class="docutils literal"><span class="pre">'time'</span></code></span></td><td><span class="yiyi-st" id="yiyi-176">内部时间</span></td></tr><tr class="row-odd"><td><span class="yiyi-st" id="yiyi-177"><code class="docutils literal"><span class="pre">'tottime'</span></code></span></td><td><span class="yiyi-st" id="yiyi-178">内部时间</span></td></tr></tbody></table><p><span class="yiyi-st" id="yiyi-179">请注意,统计信息中的所有排序都按降序排列(首先放置最耗时的项目),其中名称,文件和行号搜索按升序排列(按字母顺序排列)。</span><span class="yiyi-st" id="yiyi-180"><code class="docutils literal"><span class="pre">'nfl'</span></code>和<code class="docutils literal"><span class="pre">'stdname'</span></code>之间的细微区别是,标准名称是一种打印的名称,这意味着嵌入的行号在奇怪的方式。</span><span class="yiyi-st" id="yiyi-181">例如,第3行,第20行和第40行(如果文件名相同)将以字符串顺序20,3和40显示。</span><span class="yiyi-st" id="yiyi-182">相反,<code class="docutils literal"><span class="pre">'nfl'</span></code>执行行号的数字比较。</span><span class="yiyi-st" id="yiyi-183">事实上,<code class="docutils literal"><span class="pre">sort_stats('nfl')</span></code>与<code class="docutils literal"><span class="pre">相同sort_stats('name',</span> <span class="pre">'file',</span> <span class="pre">'line')</span></code>。</span></p><p><span class="yiyi-st" id="yiyi-184">出于向后兼容性的原因,允许数值参数<code class="docutils literal"><span class="pre">-1</span></code>,<code class="docutils literal"><span class="pre">0</span></code>,<code class="docutils literal"><span class="pre">1</span></code>和<code class="docutils literal"><span class="pre">2</span></code>。</span><span class="yiyi-st" id="yiyi-185">它们分别解释为<code class="docutils literal"><span class="pre">'stdname'</span></code>,<code class="docutils literal"><span class="pre">'calls'</span></code>,<code class="docutils literal"><span class="pre">'time'</span></code>和<code class="docutils literal"><span class="pre">'cumulative'</span></code>。</span><span class="yiyi-st" id="yiyi-186">如果使用此旧样式格式(数字),将只使用一个排序键(数字键),并且将默认忽略其他参数。</span></p></dd></dl><dl class="method"><dt id="pstats.Stats.reverse_order"><span class="yiyi-st" id="yiyi-187"> <code class="descname">reverse_order</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-188"><a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>类的此方法会反转对象中基本列表的顺序。</span><span class="yiyi-st" id="yiyi-189">请注意,默认情况下,根据所选的排序键正确选择升序或降序。</span></p></dd></dl><dl class="method"><dt id="pstats.Stats.print_stats"><span class="yiyi-st" id="yiyi-190"> <code class="descname">print_stats</code><span class="sig-paren">(</span><em>*restrictions</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-191"><a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>类的此方法按照<a class="reference internal" href="#profile.run" title="profile.run"><code class="xref py py-func docutils literal"><span class="pre">profile.run()</span></code></a>定义中所述打印报告。</span></p><p><span class="yiyi-st" id="yiyi-192">打印的顺序基于对象上的最后一个<a class="reference internal" href="#pstats.Stats.sort_stats" title="pstats.Stats.sort_stats"><code class="xref py py-meth docutils literal"><span class="pre">sort_stats()</span></code></a>操作(需要遵守<a class="reference internal" href="#pstats.Stats.add" title="pstats.Stats.add"><code class="xref py py-meth docutils literal"><span class="pre">add()</span></code></a>和<a class="reference internal" href="#pstats.Stats.strip_dirs" title="pstats.Stats.strip_dirs"><code class="xref py py-meth docutils literal"><span class="pre">strip_dirs()</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-193">提供的参数(如果有)可用于将列表限制为重要条目。</span><span class="yiyi-st" id="yiyi-194">最初,列表被视为完整的概要函数集。</span><span class="yiyi-st" id="yiyi-195">每个限制都是一个整数(以选择行数)或0.0和1.0之间的小数部分(以选择行的百分比)或正则表达式(以匹配打印的标准名称)。</span><span class="yiyi-st" id="yiyi-196">如果提供了几个限制,则它们被顺序地应用。</span><span class="yiyi-st" id="yiyi-197">例如:</span></p><pre><code class="language-python"><span></span><span class="n">print_stats</span><span class="p">(</span><span class="o">.</span><span class="mi">1</span><span class="p">,</span> <span class="s1">'foo:'</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-198">将首先将打印限制为列表的前10%,然后仅打印作为文件名<code class="file docutils literal"><span class="pre">.*foo:</span></code>的一部分的打印函数。</span><span class="yiyi-st" id="yiyi-199">相反,命令:</span></p><pre><code class="language-python"><span></span><span class="n">print_stats</span><span class="p">(</span><span class="s1">'foo:'</span><span class="p">,</span> <span class="o">.</span><span class="mi">1</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-200">将列表限制为所有具有文件名为<code class="file docutils literal"><span class="pre">.*foo:</span></code>的函数,然后继续只打印前10%的文件。</span></p></dd></dl><dl class="method"><dt id="pstats.Stats.print_callers"><span class="yiyi-st" id="yiyi-201"> <code class="descname">print_callers</code><span class="sig-paren">(</span><em>*restrictions</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-202"><a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>类的此方法将打印所有调用配置文件数据库中的每个函数的函数的列表。</span><span class="yiyi-st" id="yiyi-203">顺序与<a class="reference internal" href="#pstats.Stats.print_stats" title="pstats.Stats.print_stats"><code class="xref py py-meth docutils literal"><span class="pre">print_stats()</span></code></a>提供的顺序相同,并且限制参数的定义也是相同的。</span><span class="yiyi-st" id="yiyi-204">每个呼叫者在其自己的线路上报告。</span><span class="yiyi-st" id="yiyi-205">根据生成统计信息的剖析器,格式略有不同:</span></p><ul class="simple"><li><span class="yiyi-st" id="yiyi-206">使用<a class="reference internal" href="#module-profile" title="profile: Python source profiler."><code class="xref py py-mod docutils literal"><span class="pre">profile</span></code></a>,每个来电者后面的括号中会显示一个数字,以显示此特定来电的发送次数。</span><span class="yiyi-st" id="yiyi-207">为了方便,第二个非括号数重复在右边的函数中花费的累积时间。</span></li><li><span class="yiyi-st" id="yiyi-208">使用<a class="reference internal" href="#module-cProfile" title="cProfile"><code class="xref py py-mod docutils literal"><span class="pre">cProfile</span></code></a>,每个调用者前面都有三个数字:特定调用的次数,以及当前函数在此特定调用者调用时所花费的总时间和累积时间。</span></li></ul></dd></dl><dl class="method"><dt id="pstats.Stats.print_callees"><span class="yiyi-st" id="yiyi-209"> <code class="descname">print_callees</code><span class="sig-paren">(</span><em>*restrictions</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-210">此方法为<a class="reference internal" href="#pstats.Stats" title="pstats.Stats"><code class="xref py py-class docutils literal"><span class="pre">Stats</span></code></a>类打印由指定函数调用的所有函数的列表。</span><span class="yiyi-st" id="yiyi-211">除了这种调用方向的反转(re:called vs被调用)之外,参数和顺序与<a class="reference internal" href="#pstats.Stats.print_callers" title="pstats.Stats.print_callers"><code class="xref py py-meth docutils literal"><span class="pre">print_callers()</span></code></a>方法相同。</span></p></dd></dl></dd></dl></div><div class="section" id="what-is-deterministic-profiling"><h2><span class="yiyi-st" id="yiyi-212">27.4.5. </span><span class="yiyi-st" id="yiyi-213">What Is Deterministic Profiling?</span></h2><p><span class="yiyi-st" id="yiyi-214"><em class="dfn">确定性分析</em>意在反映所有<em>函数调用</em>,<em>函数返回</em>和<em>异常</em>并且对这些事件之间的间隔(在其期间用户的代码正在执行)进行精确的定时。</span><span class="yiyi-st" id="yiyi-215">相比之下,<em class="dfn">统计分析</em>(这不是由该模块完成)随机采样有效指令指针,并推断在哪里花费时间。</span><span class="yiyi-st" id="yiyi-216">后一种技术传统上涉及较少的开销(因为代码不需要被插桩),而是仅提供在何处花费时间的相对指示。</span></p><p><span class="yiyi-st" id="yiyi-217">在Python中,由于在执行期间有一个解释器处于活动状态,因此不需要使用检测代码来执行确定性分析。</span><span class="yiyi-st" id="yiyi-218">Python为每个事件自动提供<em class="dfn">钩子</em>(可选回调)。</span><span class="yiyi-st" id="yiyi-219">此外,Python的解释性质往往会增加如此多的开销执行,确定性分析往往只增加小的处理开销在典型的应用程序。</span><span class="yiyi-st" id="yiyi-220">结果是确定性分析不是那么昂贵,但提供了关于Python程序执行的大量运行时间统计。</span></p><p><span class="yiyi-st" id="yiyi-221">调用计数统计可用于识别代码中的错误(令人惊讶的计数),并识别可能的内联扩展点(高调用计数)。</span><span class="yiyi-st" id="yiyi-222">内部时间统计可用于识别应该仔细优化的“热环路”。</span><span class="yiyi-st" id="yiyi-223">累积时间统计应该用于识别算法选择中的高级错误。</span><span class="yiyi-st" id="yiyi-224">请注意,此分析器中累积时间的异常处理允许将算法的递归实现的统计信息直接与迭代实现进行比较。</span></p></div><div class="section" id="limitations"><h2><span class="yiyi-st" id="yiyi-225">27.4.6. </span><span class="yiyi-st" id="yiyi-226">Limitations</span></h2><p><span class="yiyi-st" id="yiyi-227">一个限制与定时信息的精度有关。</span><span class="yiyi-st" id="yiyi-228">确定性剖析器涉及精度存在一个根本问题。</span><span class="yiyi-st" id="yiyi-229">最明显的限制是,底层的“时钟”只是以约.001秒的速率(通常)打勾。</span><span class="yiyi-st" id="yiyi-230">因此,没有测量将比基础时钟更精确。</span><span class="yiyi-st" id="yiyi-231">如果进行了足够的测量,则“误差”将趋于平均。</span><span class="yiyi-st" id="yiyi-232">不幸的是,删除第一个错误会导致第二个错误来源。</span></p><p><span class="yiyi-st" id="yiyi-233">第二个问题是,从分派事件直到分析器调用获取时间实际上<em>获得</em>时钟的状态“花费一段时间”。</span><span class="yiyi-st" id="yiyi-234">类似地,从获取时钟的值的时间(然后squirreled)离开分析器事件处理程序时,有一定的延迟,直到用户的代码再次执行。</span><span class="yiyi-st" id="yiyi-235">因此,被多次调用或调用许多函数的函数通常会累积此错误。</span><span class="yiyi-st" id="yiyi-236">以这种方式累积的误差通常小于时钟的精度(小于一个时钟节拍),但<em>可以</em>累积并变得非常重要。</span></p><p><span class="yiyi-st" id="yiyi-237">使用<a class="reference internal" href="#module-profile" title="profile: Python source profiler."><code class="xref py py-mod docutils literal"><span class="pre">profile</span></code></a>比使用较低开销的<a class="reference internal" href="#module-cProfile" title="cProfile"><code class="xref py py-mod docutils literal"><span class="pre">cProfile</span></code></a>更为重要。</span><span class="yiyi-st" id="yiyi-238">出于这个原因,<a class="reference internal" href="#module-profile" title="profile: Python source profiler."><code class="xref py py-mod docutils literal"><span class="pre">profile</span></code></a>提供了为给定平台校准自身的方法,以便可以概率(平均)移除该错误。</span><span class="yiyi-st" id="yiyi-239">在分析器被校准之后,它将更准确(在最小二乘法意义上),但是它有时会产生负数(当呼叫计数异常低时,概率神对你工作: - )。 )</span><span class="yiyi-st" id="yiyi-240">不要<em></em>由配置文件中的负数报警。</span><span class="yiyi-st" id="yiyi-241">如果您已经校准了分析器,它们应该只出现<em></em>,结果实际上比没有校准更好。</span></p></div><div class="section" id="calibration"><h2><span class="yiyi-st" id="yiyi-242">27.4.7. </span><span class="yiyi-st" id="yiyi-243">Calibration</span></h2><p><span class="yiyi-st" id="yiyi-244"><a class="reference internal" href="#module-profile" title="profile: Python source profiler."><code class="xref py py-mod docutils literal"><span class="pre">profile</span></code></a>模块的分析器从每个事件处理时间中减去一个常数,以补偿调用时间函数的开销,并剔除结果。</span><span class="yiyi-st" id="yiyi-245">默认情况下,常量为0。</span><span class="yiyi-st" id="yiyi-246">以下过程可用于为给定平台获得更好的常数(见<a class="reference internal" href="#profile-limitations"><span>Limitations</span></a>)。</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">profile</span>
|
||
<span class="n">pr</span> <span class="o">=</span> <span class="n">profile</span><span class="o">.</span><span class="n">Profile</span><span class="p">()</span>
|
||
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">pr</span><span class="o">.</span><span class="n">calibrate</span><span class="p">(</span><span class="mi">10000</span><span class="p">))</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-247">该方法直接在分析器下执行由参数给定的Python调用数,并测量两者的时间。</span><span class="yiyi-st" id="yiyi-248">然后它计算每个分析器事件的隐藏开销,并将其作为float返回。</span><span class="yiyi-st" id="yiyi-249">例如,在运行Mac OS X的1.8Ghz Intel Core i5上,使用Python的time.clock()作为定时器,魔法数字约为4.04e-6。</span></p><p><span class="yiyi-st" id="yiyi-250">这个练习的目的是获得一个相当一致的结果。</span><span class="yiyi-st" id="yiyi-251">如果您的计算机<em>很快</em>,或者您的计时器功能的分辨率较差,您可能需要通过100000甚至1000000才能获得一致的结果。</span></p><p><span class="yiyi-st" id="yiyi-252">当你有一个一致的答案,有三种方式可以使用它:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">profile</span>
|
||
|
||
<span class="c1"># 1. Apply computed bias to all Profile instances created hereafter.</span>
|
||
<span class="n">profile</span><span class="o">.</span><span class="n">Profile</span><span class="o">.</span><span class="n">bias</span> <span class="o">=</span> <span class="n">your_computed_bias</span>
|
||
|
||
<span class="c1"># 2. Apply computed bias to a specific Profile instance.</span>
|
||
<span class="n">pr</span> <span class="o">=</span> <span class="n">profile</span><span class="o">.</span><span class="n">Profile</span><span class="p">()</span>
|
||
<span class="n">pr</span><span class="o">.</span><span class="n">bias</span> <span class="o">=</span> <span class="n">your_computed_bias</span>
|
||
|
||
<span class="c1"># 3. Specify computed bias in instance constructor.</span>
|
||
<span class="n">pr</span> <span class="o">=</span> <span class="n">profile</span><span class="o">.</span><span class="n">Profile</span><span class="p">(</span><span class="n">bias</span><span class="o">=</span><span class="n">your_computed_bias</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-253">如果你有一个选择,你最好选择一个较小的常数,然后你的结果将“少见”显示为负的个人资料统计。</span></p></div><div class="section" id="using-a-custom-timer"><h2><span class="yiyi-st" id="yiyi-254">27.4.8. </span><span class="yiyi-st" id="yiyi-255">Using a custom timer</span></h2><p><span class="yiyi-st" id="yiyi-256">如果要更改当前时间的确定方式(例如,强制使用挂钟时间或已用进程时间),请将所需的计时函数传递到<code class="xref py py-class docutils literal"><span class="pre">Profile</span></code>类构造函数:</span></p><pre><code class="language-python"><span></span><span class="n">pr</span> <span class="o">=</span> <span class="n">profile</span><span class="o">.</span><span class="n">Profile</span><span class="p">(</span><span class="n">your_time_func</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-257">生成的分析器将调用<code class="docutils literal"><span class="pre">your_time_func</span></code>。</span><span class="yiyi-st" id="yiyi-258">根据您是使用<a class="reference internal" href="#profile.Profile" title="profile.Profile"><code class="xref py py-class docutils literal"><span class="pre">profile.Profile</span></code></a>还是<code class="xref py py-class docutils literal"><span class="pre">cProfile.Profile</span></code>,<code class="docutils literal"><span class="pre">your_time_func</span></code>的返回值将有不同的解释:</span></p><dl class="docutils"><dt><span class="yiyi-st" id="yiyi-259"><a class="reference internal" href="#profile.Profile" title="profile.Profile"><code class="xref py py-class docutils literal"><span class="pre">profile.Profile</span></code></a></span></dt><dd><p class="first"><span class="yiyi-st" id="yiyi-260"><code class="docutils literal"><span class="pre">your_time_func</span></code>应返回单个数字或一个数字列表,其总和是当前时间(例如<a class="reference internal" href="os.html#os.times" title="os.times"><code class="xref py py-func docutils literal"><span class="pre">os.times()</span></code></a>返回)。</span><span class="yiyi-st" id="yiyi-261">如果函数返回单个时间数字,或者返回数字的列表长度为2,那么你将得到一个特别快的版本的dispatch例程。</span></p><p class="last"><span class="yiyi-st" id="yiyi-262">请注意,您应该为选择的定时器功能校准profiler类(请参见<a class="reference internal" href="#profile-calibration"><span>Calibration</span></a>)。</span><span class="yiyi-st" id="yiyi-263">对于大多数机器,返回单个整数值的定时器将在分析期间的低开销方面提供最佳结果。</span><span class="yiyi-st" id="yiyi-264">(<a class="reference internal" href="os.html#os.times" title="os.times"><code class="xref py py-func docutils literal"><span class="pre">os.times()</span></code></a>是<em>漂亮</em>坏,因为它返回一个浮点值的元组)。</span><span class="yiyi-st" id="yiyi-265">如果你想以最干净的方式替换一个更好的定时器,派生一个类,并且硬连线一个替代调度方法,最好处理你的定时器调用,以及适当的校准常数。</span></p></dd><dt><span class="yiyi-st" id="yiyi-266"><code class="xref py py-class docutils literal"><span class="pre">cProfile.Profile</span></code></span></dt><dd><p class="first"><span class="yiyi-st" id="yiyi-267"><code class="docutils literal"><span class="pre">your_time_func</span></code>应返回单个数字。</span><span class="yiyi-st" id="yiyi-268">如果它返回整数,你也可以调用类构造函数,第二个参数指定一个时间单位的实际持续时间。</span><span class="yiyi-st" id="yiyi-269">例如,如果<code class="docutils literal"><span class="pre">your_integer_time_func</span></code>返回以千秒为单位的时间,那么您将构建<code class="xref py py-class docutils literal"><span class="pre">Profile</span></code>实例如下:</span></p><pre><code class="language-python"><span></span><span class="n">pr</span> <span class="o">=</span> <span class="n">cProfile</span><span class="o">.</span><span class="n">Profile</span><span class="p">(</span><span class="n">your_integer_time_func</span><span class="p">,</span> <span class="mf">0.001</span><span class="p">)</span>
|
||
</code></pre><p class="last"><span class="yiyi-st" id="yiyi-270">由于<code class="xref py py-class docutils literal"><span class="pre">cProfile.Profile</span></code>类无法校准,应谨慎使用自定义计时器功能,并应尽可能快。</span><span class="yiyi-st" id="yiyi-271">为了使用自定义计时器的最佳结果,可能需要在内部<code class="xref py py-mod docutils literal"><span class="pre">_lsprof</span></code>模块的C源代码中对其进行硬编码。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-272">Python 3.3在<a class="reference internal" href="time.html#module-time" title="time: Time access and conversions."><code class="xref py py-mod docutils literal"><span class="pre">time</span></code></a>中添加了几个新函数,可用于精确测量进程或挂钟时间。</span><span class="yiyi-st" id="yiyi-273">例如,参见<a class="reference internal" href="time.html#time.perf_counter" title="time.perf_counter"><code class="xref py py-func docutils literal"><span class="pre">time.perf_counter()</span></code></a>。</span></p></div></div></div> |