Python 調試以及性能分析

原帖地址http://www.cnblogs.com/feisky/archive/2011/11/12/2246727.html

python pdb調試

python -m pdb myscript.py #注意這會重啓myscript.py

可以在程序中這麼設置斷點:
import pdb; pdb.set_trace()

可以修改變量的值,但是要注意,前面加上!比如要修改final的值,應該這樣!final="newvalue"

支持的命令:
    p 打印變量
    n next
    step 細點運行
    c continue
    l list
    a args 打印當前函數的參數
    condition bpnumber [condition]
    clear/disable/enable 清除/禁用/使能斷點
    q quit


python profiler性能分析

一種方法:
if __name__ == "__main__":
       import profile
       profile.run("foo()")

另一種命令行方法:python -m profile prof1.py
 
profile的統計結果分爲ncalls, tottime, percall, cumtime, percall, filename:lineno(function)等若干列:
ncalls 函數的被調用次數
tottime 函數總計運行時間,除去函數中調用的函數運行時間
percall 函數運行一次的平均時間,等於tottime/ncalls
cumtime 函數總計運行時間,含調用的函數運行時間
percall 函數運行一次的平均時間,等於cumtime/ncalls
filename:lineno(function) 函數所在的文件名,函數的行號,函數名
 
用pstats自定義報表
       profile解 決了我們的一個需求,還有一個需求:以多種形式查看輸出,我們可以通過 profile的另一個類Stats來解決。在這裏我們需要引入一個模塊pstats,它定義了一個類Stats,Stats的構造函數接受一個參數—— 就是profile的輸出文件的文件名。Stats提供了對profile輸出結果進行排序、輸出控制等功能,如我們把前文的程序改爲如下:
# …略
if __name__ == "__main__":
       import profile
       profile.run("foo()", "prof.txt")
       import pstats
       p = pstats.Stats("prof.txt")
       p.sort_stats("time").print_stats()
引入pstats之後,將profile的輸出按函數佔用的時間排序
 
Stats有若干個函數,這些函數組合能給我們輸出不同的profile報表,功能非常強大。下面簡單地介紹一下這些函數:
strip_dirs() 用以除去文件名前名的路徑信息。
add(filename,[…]) profile的輸出文件加入Stats實例中統計
dump_stats(filename) Stats的統計結果保存到文件
sort_stats(key,[…]) 最重要的一個函數,用以排序profile的輸出
reverse_order() Stats實例裏的數據反序重排
print_stats([restriction,…]) Stats報表輸出到stdout
print_callers([restriction,…])
輸出調用了指定的函數的函數的相關信息
print_callees([restriction,…]) 輸出指定的函數調用過的函數的相關信息
這裏最重要的函數就是sort_stats和print_stats,通過這兩個函數我們幾乎可以用適當的形式瀏覽所有的信息了,下面來詳細介紹一下。
sort_stats() 接受一個或者多個字符串參數,如”time”、”name” 等,表明要根據哪一列來排序,這相當有用,例如我們可以通過用time爲key來排序得知最消耗時間的函數,也可以通過cumtime來排序,獲知總消耗 時間最多的函數,這樣我們優化的時候就有了針對性,也就事半功倍了。sort_stats可接受的參數如下:
‘ncalls’ 被調用次數
‘cumulative’ 函數運行的總時間
‘file’ 文件名
‘module’ 文件名
‘pcalls’ 簡單調用統計(兼容舊版,未統計遞歸調用)
‘line’ 行號
‘name’ 函數名
‘nfl’ Name/file/line
‘stdname’ 標準函數名
‘time’ 函數內部運行時間(不計調用子函數的時間)
       另一個相當重要的函數就是print_stats——用以根據最後一次調用sort_stats之後得到的報表。
 
cProfile

python -m cProfile -s time test.py

 
timeit

如果我們某天心血來潮,想要向list裏append一個元素需要多少時間或者想知道拋出一個異常要多少時間,那使用profile就好像用牛刀殺雞了。這時候我們更好的選擇是timeit模塊。

timeit除了有非常友好的編程接口,也同樣提供了友好的命令行接口。首先來看看編程接口。timeit模塊包含一個類Timer,它的構造函數是這樣的:
class Timer( [stmt='pass' [, setup='pass' [, timer=<timer function>]]])
stmt參數是字符串形式的一個代碼段,這個代碼段將被評測運行時間;setup參數用以設置stmt的運行環境;timer可以由用戶使用自定義精度的計時函數。
     
 timeit.Timer有三個成員函數,下面簡單介紹一下:
timeit( [number=1000000])
timeit()執行一次Timer構造函數中的setup語句之後,就重複執行number次stmt語句,然後返回總計運行消耗的時間。
repeat( [repeat=3 [, number=1000000]])
repeat()函數以number爲參數調用timeit函數repeat次,並返回總計運行消耗的時間
print_exc( [file=None])
print_exc()函數用以代替標準的tracback,原因在於print_exc()會輸出錯行的源代碼,如:
>>> t = timeit.Timer("t = foo()/nprint t")      ßtimeit的代碼段
>>> t.timeit()
 
Traceback (most recent call last):
 File "<pyshell#12>", line 1, in -toplevel-
    t.timeit()
 File "E:/Python23/lib/timeit.py", line 158, in timeit
    return self.inner(it, self.timer)
 File "<timeit-src>", line 6, in inner
    foo()         ß標準輸出是這樣的
NameError: global name 'foo' is not defined
>>> try:
       t.timeit()
except:
       t.print_exc()
 
      
Traceback (most recent call last):
 File "<pyshell#17>", line 2, in ?
 File "E:/Python23/lib/timeit.py", line 158, in timeit
    return self.inner(it, self.timer)
 File "<timeit-src>", line 6, in inner
    t = foo()        ßprint_exc()的輸出是這樣的,方便定位錯誤
NameError: global name 'foo' is not defined
       除了可以使用timeit的編程接口外,我們也可以在命令行裏使用timeit,非常方便:
python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
其中參數的定義如下:
-n N/--number=N
       statement語句執行的次數
-r N/--repeat=N
       重複多少次調用timeit(),默認爲3
-s S/--setup=S
       用以設置statement執行環境的語句,默認爲”pass”
-t/--time
       計時函數,除了Windows平臺外默認使用time.time()函數,
-c/--clock
       計時函數,Windows平臺默認使用time.clock()函數
-v/--verbose
       輸出更大精度的計時數值
-h/--help
       簡單的使用幫助
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章