Cython--Python和Cython代碼的性能分析(二)

Profile tutorial–性能分析

參考: http://docs.cython.org/en/latest/src/tutorial/profiling_tutorial.html
github代碼: https://github.com/chenyangMl/cython-pro/tree/master/Profile

性能分析:指通過性能測試報告對所寫代碼進行整體和局部(函數)的運行效率分析,爲後續的性能優化提供決策支持。

1. 純python的性能分析

分析案例:

  • 1 自己寫的python代碼文件calc_pi.py

    # calc_pi.py
    
    def recip_square(i):
        return 1. / i ** 2
    
    def approx_pi(n=10000000):
        val = 0.
        for k in range(1, n + 1):
            val += recip_square(k)
        return (6 * val) ** .5
    
  • 2 編寫性能分析腳本python_profile.py

    # python_profile.py
    
    import pstats, cProfile
    
    import calc_pi
    
    cProfile.runctx("calc_pi.approx_pi()", globals(), locals(), "Profile.prof")
    
    s = pstats.Stats("Profile.prof")
    s.strip_dirs().sort_stats("time").print_stats()
    

    運行性能分析腳步,結果如下:

             10000004 function calls in 3.361 seconds
    
       Ordered by: internal time
    
       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     10000000    2.439    0.000    2.439    0.000 calc_pi.py:3(recip_square)
            1    0.922    0.922    3.361    3.361 calc_pi.py:6(approx_pi)
            1    0.000    0.000    3.361    3.361 {built-in method builtins.exec}
            1    0.000    0.000    3.361    3.361 <string>:1(<module>)
            1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    
Type 備註
ncalls 函數被調用的次數
tottime 函數內部消耗的總時間
percall 函數的平均調用時間,tottime/ncalls
cumtime 之前所有子函數消費時間的累計和
filename:lineno(function) 被分析函數所在文件名、行號、函數名。

2. Cython的性能分析

  • 1、自己的Cython代碼,calc_pi.pyx文件

    # cython: profile=True
    
    # calc_pi.pyx
    
    def recip_square(int i):
        return 1. / i ** 2
    
    def approx_pi(int n=10000000):
        cdef double val = 0.
        cdef int k
        for k in range(1, n + 1):
            val += recip_square(k)
        return (6 * val) ** .5
    

    注意 上述第一行# cython: profile=True是顯示告訴Cython啓用分析,必須加上。

  • 2、性能分析腳步cython_profile.py

    # cython_profile.py
    
    import pstats, cProfile
    
    import pyximport
    pyximport.install()
    
    import calc_pi
    
    cProfile.runctx("calc_pi.approx_pi()", globals(), locals(), "Profile.prof")
    
    s = pstats.Stats("Profile.prof")
    s.strip_dirs().sort_stats("time").print_stats()
    

    運行性能分析腳步,結果如下:

             10000004 function calls in 3.146 seconds
    
       Ordered by: internal time
    
       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     10000000    2.233    0.000    2.233    0.000 calc_pi.py:2(recip_square)
            1    0.914    0.914    3.146    3.146 calc_pi.py:5(approx_pi)
            1    0.000    0.000    3.146    3.146 {built-in methodcy builtins.exec}
            1    0.000    0.000    3.146    3.146 <string>:1(<module>)
            1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    

    當需要cProfile.runctx進行傳參性能分析時,通過global或local將參數以字典的形式傳入。

    cProfile.runctx("calc_pi.approx_pi(n)", globals(), locals={"n":15000}, "Profile.prof")
    
  • 3 基於性能分析內容進行代碼優化。

  • 4 關閉對某個函數的性能分析,只需要在函數加一個@cython.profile(False)的裝飾器即可,如停止對函數recip_square的性能分析:

    cimport cython
    @cython.profile(False)
    def recip_square(int i):
        return 1. / i ** 2
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章