摘要:性能分析和調(diào)優(yōu)工具簡(jiǎn)介總會(huì)遇到一個(gè)時(shí)候你會(huì)想提高程序執(zhí)行效率,想看看哪部分耗時(shí)長(zhǎng)成為瓶頸,想知道程序運(yùn)行時(shí)內(nèi)存和使用情況。安裝會(huì)分析的更快。
性能分析和調(diào)優(yōu)工具簡(jiǎn)介
總會(huì)遇到一個(gè)時(shí)候你會(huì)想提高程序執(zhí)行效率,想看看哪部分耗時(shí)長(zhǎng)成為瓶頸,想知道程序運(yùn)行時(shí)內(nèi)存和CPU使用情況。這時(shí)候你會(huì)需要一些方法對(duì)程序進(jìn)行性能分析和調(diào)優(yōu)。
By Context Manager可以上下文管理器自己實(shí)現(xiàn)一個(gè)計(jì)時(shí)器, 參見(jiàn)之前的介紹 timeit 文章里做的那樣,通過(guò)定義類(lèi)的 __enter__ 和 __exit__ 方法來(lái)實(shí)現(xiàn)對(duì)管理的函數(shù)計(jì)時(shí), 類(lèi)似如:
# timer.py import time class Timer(object): def __init__(self, verbose=False): self.verbose = verbose def __enter__(self): self.start = time.time() return self def __exit__(self, *args): self.end = time.time() self.secs = self.end - self.start self.msecs = self.secs * 1000 # 毫秒 if self.verbose: print "elapsed time: %f ms" % self.msecs
使用方式如下:
from timer import Timer with Timer() as t: foo() print "=> foo() spends %s s" % t.secsBy Decorator
然而我認(rèn)為裝飾器的方式更加優(yōu)雅
import time from functools import wraps def timer(function): @wraps(function) def function_timer(*args, **kwargs): t0 = time.time() result = function(*args, **kwargs) t1 = time.time() print ("Total time running %s: %s seconds" % (function.func_name, str(t1-t0)) ) return result return function_timer
使用就很簡(jiǎn)單了:
@timer def my_sum(n): return sum([i for i in range(n)]) if __name__ == "__main__": my_sum(10000000)
運(yùn)行結(jié)果:
? python profile.py Total time running my_sum: 0.817697048187 seconds系統(tǒng)自帶的time命令
使用示例如下:
? time python profile.py Total time running my_sum: 0.854454040527 seconds python profile.py 0.79s user 0.18s system 98% cpu 0.977 total
上面的結(jié)果說(shuō)明: 執(zhí)行腳本消耗0.79sCPU時(shí)間, 0.18秒執(zhí)行內(nèi)核函數(shù)消耗的時(shí)間,總共0.977s時(shí)間。
其中, total時(shí)間 - (user時(shí)間 + system時(shí)間) = 消耗在輸入輸出和系統(tǒng)執(zhí)行其它任務(wù)消耗的時(shí)間
可以用來(lái)做benchmark, 可以方便的重復(fù)一個(gè)程序執(zhí)行的次數(shù),來(lái)查看程序可以運(yùn)行多塊。具體參考之前寫(xiě)的文章。
cProfile直接看帶注釋的使用示例吧。
#coding=utf8 def sum_num(max_num): total = 0 for i in range(max_num): total += i return total def test(): total = 0 for i in range(40000): total += i t1 = sum_num(100000) t2 = sum_num(200000) t3 = sum_num(300000) t4 = sum_num(400000) t5 = sum_num(500000) test2() return total def test2(): total = 0 for i in range(40000): total += i t6 = sum_num(600000) t7 = sum_num(700000) return total if __name__ == "__main__": import cProfile # # 直接把分析結(jié)果打印到控制臺(tái) # cProfile.run("test()") # # 把分析結(jié)果保存到文件中 # cProfile.run("test()", filename="result.out") # 增加排序方式 cProfile.run("test()", filename="result.out", sort="cumulative")
cProfile將分析的結(jié)果保存到result.out文件中,但是以二進(jìn)制形式存儲(chǔ)的,想直接查看的話(huà)用提供的 pstats 來(lái)查看。
import pstats # 創(chuàng)建Stats對(duì)象 p = pstats.Stats("result.out") # strip_dirs(): 去掉無(wú)關(guān)的路徑信息 # sort_stats(): 排序,支持的方式和上述的一致 # print_stats(): 打印分析結(jié)果,可以指定打印前幾行 # 和直接運(yùn)行cProfile.run("test()")的結(jié)果是一樣的 p.strip_dirs().sort_stats(-1).print_stats() # 按照函數(shù)名排序,只打印前3行函數(shù)的信息, 參數(shù)還可為小數(shù),表示前百分之幾的函數(shù)信息 p.strip_dirs().sort_stats("name").print_stats(3) # 按照運(yùn)行時(shí)間和函數(shù)名進(jìn)行排序 p.strip_dirs().sort_stats("cumulative", "name").print_stats(0.5) # 如果想知道有哪些函數(shù)調(diào)用了sum_num p.print_callers(0.5, "sum_num") # 查看test()函數(shù)中調(diào)用了哪些函數(shù) p.print_callees("test")
截取一個(gè)查看test()調(diào)用了哪些函數(shù)的輸出示例:
? python python profile.py Random listing order was used List reduced from 6 to 2 due to restriction <"test"> Function called... ncalls tottime cumtime profile.py:24(test2) -> 2 0.061 0.077 profile.py:3(sum_num) 1 0.000 0.000 {range} profile.py:10(test) -> 5 0.073 0.094 profile.py:3(sum_num) 1 0.002 0.079 profile.py:24(test2) 1 0.001 0.001 {range}profile.Profile
cProfile還提供了可以自定義的類(lèi),可以更精細(xì)的分析, 具體看文檔。
格式如: class profile.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)
下面這個(gè)例子來(lái)自官方文檔:
import cProfile, pstats, StringIO pr = cProfile.Profile() pr.enable() # ... do something ... pr.disable() s = StringIO.StringIO() sortby = "cumulative" ps = pstats.Stats(pr, stream=s).sort_stats(sortby) ps.print_stats() print s.getvalue()lineprofiler
lineprofiler是一個(gè)對(duì)函數(shù)進(jìn)行逐行性能分析的工具,可以參見(jiàn)github項(xiàng)目說(shuō)明,地址: https://github.com/rkern/line...
示例#coding=utf8 def sum_num(max_num): total = 0 for i in range(max_num): total += i return total @profile # 添加@profile 來(lái)標(biāo)注分析哪個(gè)函數(shù) def test(): total = 0 for i in range(40000): total += i t1 = sum_num(10000000) t2 = sum_num(200000) t3 = sum_num(300000) t4 = sum_num(400000) t5 = sum_num(500000) test2() return total def test2(): total = 0 for i in range(40000): total += i t6 = sum_num(600000) t7 = sum_num(700000) return total test()
通過(guò) kernprof 命令來(lái)注入分析,運(yùn)行結(jié)果如下:
? kernprof -l -v profile.py Wrote profile results to profile.py.lprof Timer unit: 1e-06 s Total time: 3.80125 s File: profile.py Function: test at line 10 Line # Hits Time Per Hit % Time Line Contents ============================================================== 10 @profile 11 def test(): 12 1 5 5.0 0.0 total = 0 13 40001 19511 0.5 0.5 for i in range(40000): 14 40000 19066 0.5 0.5 total += i 15 16 1 2974373 2974373.0 78.2 t1 = sum_num(10000000) 17 1 58702 58702.0 1.5 t2 = sum_num(200000) 18 1 81170 81170.0 2.1 t3 = sum_num(300000) 19 1 114901 114901.0 3.0 t4 = sum_num(400000) 20 1 155261 155261.0 4.1 t5 = sum_num(500000) 21 1 378257 378257.0 10.0 test2() 22 23 1 2 2.0 0.0 return total
hits(執(zhí)行次數(shù)) 和 time(耗時(shí)) 值高的地方是有比較大優(yōu)化空間的地方。
memoryprofiler類(lèi)似于"lineprofiler"對(duì)基于行分析程序內(nèi)存使用情況的模塊。github 地址:https://github.com/fabianp/me... 。ps:安裝 psutil, 會(huì)分析的更快。
同樣是上面"lineprofiler"中的代碼,運(yùn)行 python -m memory_profiler profile.py 命令生成結(jié)果如下:
? python -m memory_profiler profile.py Filename: profile.py Line # Mem usage Increment Line Contents ================================================ 10 24.473 MiB 0.000 MiB @profile 11 def test(): 12 24.473 MiB 0.000 MiB total = 0 13 25.719 MiB 1.246 MiB for i in range(40000): 14 25.719 MiB 0.000 MiB total += i 15 16 335.594 MiB 309.875 MiB t1 = sum_num(10000000) 17 337.121 MiB 1.527 MiB t2 = sum_num(200000) 18 339.410 MiB 2.289 MiB t3 = sum_num(300000) 19 342.465 MiB 3.055 MiB t4 = sum_num(400000) 20 346.281 MiB 3.816 MiB t5 = sum_num(500000) 21 356.203 MiB 9.922 MiB test2() 22 23 356.203 MiB 0.000 MiB return totalTODO objgraph 參考資料:
https://docs.python.org/2/lib...
http://xianglong.me/article/a...
http://www.cnblogs.com/btchen...
https://www.huyng.com/posts/p...
http://www.marinamele.com/7-t...
NEXT 代碼的調(diào)優(yōu)tips文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/44260.html
摘要:主要用途為查找是否有公開(kāi)的網(wǎng)站為。但缺點(diǎn)是該網(wǎng)站限制網(wǎng)絡(luò)發(fā)包的速度,采用了單線(xiàn)程的方式,掃描耗時(shí)較長(zhǎng)。希望本篇文章能對(duì)你有所幫助,有錯(cuò)誤的地方,歡迎指出喜歡的話(huà),不要忘記點(diǎn)贊哦 ...
摘要:火爆是當(dāng)今非常熱門(mén)的語(yǔ)言之一,根據(jù)年月編程語(yǔ)言排行,榮獲年度編程語(yǔ)言稱(chēng)號(hào),并且其流行度依然處在上升勢(shì)頭。學(xué)習(xí)完技能樹(shù)之后,你將進(jìn)入編程的大門(mén),明白編程的作用,建立編程的興趣方法和習(xí)慣。 ? 作者主頁(yè):不吃西紅柿? ? 簡(jiǎn)介:CSDN博客專(zhuān)家?、HDZ核心組成員? 、Python領(lǐng)域優(yōu)質(zhì)創(chuàng)作者...
摘要:根據(jù)在年的調(diào)查顯示,近的數(shù)據(jù)科學(xué)家使用作為主要的編程語(yǔ)言,每一次的進(jìn)步都是它成為數(shù)據(jù)分析主流工具的重要因素。根據(jù)進(jìn)行的一項(xiàng)調(diào)查顯示,在上的月活躍用戶(hù)的占比在年后大幅上升。 昨天,微信的Python交流群出現(xiàn)了這樣的對(duì)話(huà): showImg(https://segmentfault.com/img/bVbjV16?w=700&h=425); 看到這部分代碼交流,讓我不禁感受到Python的...
摘要:是一個(gè)文章內(nèi)容提取器,可以從任意資訊文章類(lèi)的網(wǎng)頁(yè)中提取文章主體,并提取標(biāo)題標(biāo)簽摘要圖片視頻等信息,且支持中文網(wǎng)頁(yè)。 爬蟲(chóng)抓取數(shù)據(jù)有兩個(gè)頭疼的點(diǎn),寫(xiě)過(guò)爬蟲(chóng)的小伙伴們一定都深有體會(huì): 網(wǎng)站的 防抓取 機(jī)制。你要盡可能將自己偽裝成一個(gè)人,騙過(guò)對(duì)方的服務(wù)器反爬驗(yàn)證。 網(wǎng)站的 內(nèi)容提取 。每個(gè)網(wǎng)站都需要你做不同的處理,而且網(wǎng)站一旦改版,你的代碼也得跟著更新。 第一點(diǎn)沒(méi)什么捷徑可走,套路見(jiàn)得多...
閱讀 2453·2021-11-23 09:51
閱讀 503·2019-08-30 13:59
閱讀 1820·2019-08-29 11:20
閱讀 2529·2019-08-26 13:41
閱讀 3239·2019-08-26 12:16
閱讀 729·2019-08-26 10:59
閱讀 3321·2019-08-26 10:14
閱讀 602·2019-08-23 17:21