繁体   English   中英

我如何找出我的代码的哪些部分在Python中效率低下

[英]How do I find out what parts of my code are inefficient in Python

在上一个问题中,我问到有关多处理的问题,即使用多个内核使程序运行更快,有人告诉我:

通常情况下,与4倍的改进和多处理的额外复杂度相比,您可以获得100倍以上的优化和更好的代码

然后他们建议我应该:

使用探查器了解缓慢的原因,然后集中精力对其进行优化。

因此,我想到了一个问题: 如何描述脚本?

在这里,我找到了cProfile并将其实现为一些测试代码以查看其工作原理。

这是我的代码:

import cProfile

def foo():
    for i in range(10000):
        a = i**i
        if i % 1000 == 0:
            print(i)

cProfile.run('foo()')

但是,运行它之后,这就是我得到的:

0
1000
2000
3000
4000
5000
6000
7000
8000
9000
         1018 function calls in 20.773 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   20.773   20.773 <string>:1(<module>)
      147    0.000    0.000    0.000    0.000 rpc.py:150(debug)
       21    0.000    0.000    0.050    0.002 rpc.py:213(remotecall)
       21    0.000    0.000    0.002    0.000 rpc.py:223(asynccall)
       21    0.000    0.000    0.048    0.002 rpc.py:243(asyncreturn)
       21    0.000    0.000    0.000    0.000 rpc.py:249(decoderesponse)
       21    0.000    0.000    0.048    0.002 rpc.py:287(getresponse)
       21    0.000    0.000    0.000    0.000 rpc.py:295(_proxify)
       21    0.001    0.000    0.048    0.002 rpc.py:303(_getresponse)
       21    0.000    0.000    0.000    0.000 rpc.py:325(newseq)
       21    0.000    0.000    0.002    0.000 rpc.py:329(putmessage)
       21    0.000    0.000    0.000    0.000 rpc.py:55(dumps)
       20    0.000    0.000    0.001    0.000 rpc.py:556(__getattr__)
        1    0.000    0.000    0.001    0.001 rpc.py:574(__getmethods)
       20    0.000    0.000    0.000    0.000 rpc.py:598(__init__)
       20    0.000    0.000    0.050    0.002 rpc.py:603(__call__)
       20    0.000    0.000    0.051    0.003 run.py:340(write)
        1   20.722   20.722   20.773   20.773 test.py:3(foo)
       42    0.000    0.000    0.000    0.000 threading.py:1226(current_thread)
       21    0.000    0.000    0.000    0.000 threading.py:215(__init__)
       21    0.000    0.000    0.047    0.002 threading.py:263(wait)
       21    0.000    0.000    0.000    0.000 threading.py:74(RLock)
       21    0.000    0.000    0.000    0.000 {built-in method _struct.pack}
       21    0.000    0.000    0.000    0.000 {built-in method _thread.allocate_lock}
       42    0.000    0.000    0.000    0.000 {built-in method _thread.get_ident}
        1    0.000    0.000   20.773   20.773 {built-in method builtins.exec}
       42    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}
       63    0.000    0.000    0.000    0.000 {built-in method builtins.len}
       10    0.000    0.000    0.051    0.005 {built-in method builtins.print}
       21    0.000    0.000    0.000    0.000 {built-in method select.select}
       21    0.000    0.000    0.000    0.000 {method '_acquire_restore' of '_thread.RLock' objects}
       21    0.000    0.000    0.000    0.000 {method '_is_owned' of '_thread.RLock' objects}
       21    0.000    0.000    0.000    0.000 {method '_release_save' of '_thread.RLock' objects}
       21    0.000    0.000    0.000    0.000 {method 'acquire' of '_thread.RLock' objects}
       42    0.047    0.001    0.047    0.001 {method 'acquire' of '_thread.lock' objects}
       21    0.000    0.000    0.000    0.000 {method 'append' of 'collections.deque' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
       21    0.000    0.000    0.000    0.000 {method 'dump' of '_pickle.Pickler' objects}
       20    0.000    0.000    0.000    0.000 {method 'get' of 'dict' objects}
       21    0.000    0.000    0.000    0.000 {method 'getvalue' of '_io.BytesIO' objects}
       21    0.000    0.000    0.000    0.000 {method 'release' of '_thread.RLock' objects}
       21    0.001    0.000    0.001    0.000 {method 'send' of '_socket.socket' objects}

我希望它能显示出我的代码哪些部分花费了最长的时间,例如,它表明a = i**i花费了最长的计算时间,但是我可以从它告诉我的所有信息中收集到的是foo()函数花费了最长的时间,但是在该函数中花费了最长的时间我对数据一无所知。

另外,当我将其实现到实际代码中时,它也会执行相同的操作。 一切都在函数中,它仅告诉我哪些函数花费的时间最长,而不是函数花费的时间如此长。

所以这是我的主要问题:

  1. 我如何查看该函数内部的内容使代码花费这么长时间(我什cProfile应该使用cProfile吗?)

  2. 一旦知道使用最多的CPU是什么,设置最佳代码的最佳方法是什么?

注意:我的RAM和磁盘等绝对不错,只是CPU被用尽了(12%的CPU,因为它仅在单个内核上运行)

我如何查看该函数内部的内容使代码花费这么长时间(我什至应该使用cProfile?)

是的,您可以使用cProfile但是您提出问题的方式让我怀疑line_profiler (第三方模块,您需要安装它)不是更好的工具。

当我要分析一个函数时,我正在使用此包的IPython / Jupyter绑定:

%load_ext line_profiler

实际分析功能:

%lprun -f foo foo()
#             ^^^^^---- this call will be profiled
#         ^^^-----------function to profile

产生以下输出:

Timer unit: 5.58547e-07 s

Total time: 17.1189 s
File: <ipython-input-1-21b5a5f52f66>
Function: foo at line 1

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     1                                           def foo():
     2     10001        31906      3.2      0.1      for i in range(10000):
     3     10000     30534065   3053.4     99.6          a = i**i
     4     10000        75998      7.6      0.2          if i % 1000 == 0:
     5        10         6953    695.3      0.0              print(i)

这包括可能有趣的几件事。 例如,有99.6%的时间花费在i**i行中。

  1. 一旦知道使用最多的CPU是什么,设置最佳代码的最佳方法是什么?

那要看。 有时您需要使用不同的函数/数据结构/算法-有时您无能为力。 但是至少您知道瓶颈在哪里,并且可以估计瓶颈或其他地方的更改将产生多大影响。

正如您在分析日志中注意到的那样, cProfile最大分辨率是function

所以:

  • 如果你的函数是小你可以找出哪些部分占用了很长的时间(虽然有时很难与内置电话一样in
  • 如果您的函数很大,也许是时候将其缩减为较小的函数,使其变得“可配置”,但是函数调用开销可能会减慢速度

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM