<option id="mwy0y"><strong id="mwy0y"></strong></option>
  • <ul id="mwy0y"><sup id="mwy0y"></sup></ul>
  • <ul id="mwy0y"></ul>
  • <del id="mwy0y"><dfn id="mwy0y"></dfn></del><ul id="mwy0y"><sup id="mwy0y"></sup></ul>
  • <abbr id="mwy0y"></abbr>

    千鋒教育-做有情懷、有良心、有品質的職業教育機構

    400-811-9990
    手機站
    千鋒教育

    千鋒學習站 | 隨時隨地免費學

    千鋒教育

    掃一掃進入千鋒手機站

    領取全套視頻
    千鋒教育

    關注千鋒學習站小程序
    隨時隨地免費學習課程

    上海
    • 北京
    • 鄭州
    • 武漢
    • 成都
    • 西安
    • 沈陽
    • 廣州
    • 南京
    • 深圳
    • 大連
    • 青島
    • 杭州
    • 重慶
    當前位置:長沙千鋒IT培訓  >  技術干貨  >  Python性能分析

    Python性能分析

    來源:千鋒教育
    發布人:xqq
    時間: 2023-11-08 18:08:16

    python標準庫提供兩個代碼性能分析相關的模塊,即timeit和cProfile/profile。前者更適合測試簡短的代碼片段,后者則可分析代碼片段乃至整體模塊中各個函數的調用次數、運行耗時等信息。

    cProfile是profile的C版本,開銷更小。基于cProfile模塊,可方便地評估程序性能瓶頸(bottleneck),借以發現程序中值得優化的短板。

    根據粒度不同,可將cProfile使用場景分為三類。

    1.1分析單條語句

    importcProfile,pstats,re,cStringIO

    cProfile.run('re.compile("foo|bar")','prfRes')#將cProfile的結果寫入prfRes文件

    p=pstats.Stats('prfRes')#pstats讀取cProfile輸出結果

    #strip_dirs()剝除模塊名的無關路徑(如C:\Python27\lib\)

    #sort_stats('cumtime')或sort_stats('cumulative')按照cumtime對打印項排序

    #print_stats(n)打印輸出前10行統計項(不指定n則打印所有項)

    p.strip_dirs().sort_stats('cumtime').print_stats(5)

    pstats模塊可用多種方式對cProfile性能分析結果進行排序并輸出。運行結果如下:

    TueMay2413:56:072016prfRes

    195functioncalls(190primitivecalls)in0.001seconds

    Orderedby:cumulativetime

    Listreducedfrom33to5duetorestriction<5>

    ncallstottimepercallcumtimepercallfilename:lineno(function)

    10.0000.0000.0010.001:1()

    10.0000.0000.0010.001re.py:192(compile)

    10.0000.0000.0010.001re.py:230(_compile)

    10.0000.0000.0010.001sre_compile.py:567(compile)

    10.0000.0000.0000.000sre_compile.py:552(_code)

    其中,tottime表示某函數的總計運行時間(不含該函數內調用的子函數運行時間),cumtime表示某函數及其調用的子函數的累積運行時間。

    1.2分析代碼片段

    pr=cProfile.Profile()

    pr.enable()#以下為待分析代碼段

    regMatch=re.match('^([^/]*)/(/|\*)+(.*)$','//*suspicious')

    printregMatch.groups()

    pr.disable()#以上為待分析代碼段

    s=cStringIO.StringIO()

    pstats.Stats(pr,stream=s).sort_stats('cumulative').print_stats(10)

    prints.getvalue()

    運行結果如下:

    ('','*','suspicious')

    536functioncalls(512primitivecalls)in0.011seconds

    Orderedby:cumulativetime

    Listreducedfrom78to10duetorestriction<10>

    ncallstottimepercallcumtimepercallfilename:lineno(function)

    20.0000.0000.0090.005C:\Python27\lib\idlelib\PyShell.py:1343(write)

    20.0000.0000.0090.005C:\Python27\lib\idlelib\rpc.py:591(__call__)

    20.0000.0000.0090.005C:\Python27\lib\idlelib\rpc.py:208(remotecall)

    20.0000.0000.0090.004C:\Python27\lib\idlelib\rpc.py:238(asyncreturn)

    20.0000.0000.0090.004C:\Python27\lib\idlelib\rpc.py:279(getresponse)

    20.0000.0000.0090.004C:\Python27\lib\idlelib\rpc.py:295(_getresponse)

    20.0000.0000.0090.004C:\Python27\lib\threading.py:309(wait)

    80.0090.0010.0090.001{method'acquire'of'thread.lock'objects}

    10.0000.0000.0020.002C:\Python27\lib\re.py:138(match)

    10.0000.0000.0020.002C:\Python27\lib\re.py:230(_compile)

    1.3分析整個模塊

    使用命令行,調用cProfile腳本分析其他腳本文件。命令格式為:

    python-mcProfile[-ooutput_file][-ssort_order]myscript.py

    注意,-o和-s選項不可同時使用。

    以C代碼統計工具為例,運行如下命令:

    E:\PyTest>python-mcProfile-stottimeCLineCounter.pysource-d-b>out.txt

    截取out.txt文件部分內容如下:

    250316245433620.25xtm_mgr.c

    1408729374932093169380.26

    762068functioncalls(762004primitivecalls)in2.967seconds

    Orderedby:internaltime

    ncallstottimepercallcumtimepercallfilename:lineno(function)

    820.9850.0122.8690.035CLineCounter.py:11(CalcLines)

    1176400.6120.0001.3150.000re.py:138(match)

    1176500.3810.0000.3810.000{method'match'of'_sre.SRE_Pattern'objects}

    1176550.3190.0000.3240.000re.py:230(_compile)

    1380500.1980.0000.1980.000{method'isspace'of'str'objects}

    1058230.1650.0000.1650.000{method'strip'of'str'objects}

    123156/1231410.1540.0000.1540.000{len}

    378870.0550.0000.0550.000{method'group'of'_sre.SRE_Match'objects}

    820.0410.0000.0410.000{method'readlines'of'file'objects}

    820.0160.0000.0160.000{open}

    10.0040.0042.9502.950CLineCounter.py:154(CountDir)

    由tottime可見,此處的性能瓶頸在于CalcLines()函數和其中的正則表達式處理。而isspace()和strip()方法及len()函數因調用次數較多,總的耗時也頗為可觀。

    作為對比,以下給出一種未使用正則表達式的統計實現:

    defCalcLines(line,isBlockComment):

    lineType,lineLen=0,len(line)

    line=line+'\n'#添加一個字符防止iChar+1時越界

    iChar,isLineComment=0,False

    whileiChar

    #行結束符(Windows:\r\n;Mac:\r;Unix:\n)

    ifline[iChar]=='\r'orline[iChar]=='\n':

    break

    elifline[iChar]==''orline[iChar]=='\t':#空白字符

    iChar+=1;continue

    elifline[iChar]=='/'andline[iChar+1]=='/':#行注釋

    isLineComment=True

    lineType|=2;iChar+=1#跳過'/'

    elifline[iChar]=='/'andline[iChar+1]=='*':#塊注釋開始符

    isBlockComment[0]=True

    lineType|=2;iChar+=1

    elifline[iChar]=='*'andline[iChar+1]=='/':#塊注釋結束符

    isBlockComment[0]=False

    lineType|=2;iChar+=1

    else:

    ifisLineCommentorisBlockComment[0]:

    lineType|=2

    else:

    lineType|=1

    iChar+=1

    returnlineType#Bitmap:0空行,1代碼,2注釋,3代碼和注釋

    在CalcLines()函數中。參數line為當前文件行字符串,參數isBlockComment指示當前行是否位于塊注釋內。該函數直接分析句法,而非模式匹配。注意,行結束符可能因操作系統而異,因此應區分CR(回車)和LF(換行)符。此外,也可在讀取文件時采用"rU"(即通用換行模式),該模式會將行結束符\r\n和\r替換為\n。

    基于新的CalcLines()函數,CountFileLines()函數需作如下修改:

    defCountFileLines(filePath,isRawReport=True,isShortName=False):

    fileExt=os.path.splitext(filePath)

    iffileExt[1]!='.c'andfileExt[1]!='.h':

    return

    isBlockComment=[False]#或定義為全局變量,以保存上次值

    lineCountInfo=[0]*4#[代碼總行數,代碼行數,注釋行數,空白行數]

    withopen(filePath,'r')asfile:

    forlineinfile:

    lineType=CalcLines(line,isBlockComment)

    lineCountInfo[0]+=1

    iflineType==0:lineCountInfo[3]+=1

    eliflineType==1:lineCountInfo[1]+=1

    eliflineType==2:lineCountInfo[2]+=1

    eliflineType==3:lineCountInfo[1]+=1;lineCountInfo[2]+=1

    else:

    assertFalse,'UnexpectedlineType:%d(0~3)!'%lineType

    ifisRawReport:

    globalrawCountInfo

    rawCountInfo[:-1]=[x+yforx,yinzip(rawCountInfo[:-1],lineCountInfo)]

    rawCountInfo[-1]+=1

    elifisShortName:

    detailCountInfo.append([os.path.basename(filePath),lineCountInfo])

    else:

    detailCountInfo.append([filePath,lineCountInfo])

    將這種統計實現命名為BCLineCounter.py。通過cProfile命令分析其性能,截取out.txt文件部分內容如下:

    250316245433620.25xtm_mgr.c

    1408729373632106169380.26

    286013functioncalls(285979primitivecalls)in3.926seconds

    Orderedby:internaltime

    ncallstottimepercallcumtimepercallfilename:lineno(function)

    1408723.3340.0003.4750.000BCLineCounter.py:15(CalcLines)

    830.4090.0053.9030.047BCLineCounter.py:45(CountFileLines)

    141593/1415850.1420.0000.1420.000{len}

    820.0140.0000.0140.000{open}

    10.0040.0040.0040.004collections.py:1()

    4160.0030.0000.0040.000ntpath.py:96(splitdrive)

    840.0020.0000.0020.000{nt._isdir}

    10.0020.0020.0070.007argparse.py:62()

    10.0020.0023.9263.926BCLineCounter.py:6()

    可見,性能并不如CLineCounter.py。因此,使用標準庫(如re)提供的函數或方法,不失為明智的選擇。

    此外,對比BCLineCounter.py和CLineCounter.py的詳細行數報告可知,兩者的統計結果存在細微差異(正負誤差不超過5行)。差異主要體現在有效代碼行和純注釋行統計上,因為總行數和空白行數通常不會出現統計誤差。那么,哪種實現更可靠呢?

    作者首先想到挑選存在統計差異的文件,人工或半人工地刪除純注釋行和空白行,從而得到精確的有效代碼行數。之所以不編寫腳本自動刪除上述類型的文件行,是因為作者對于注釋行的解析已經存在誤差,無法作為基準參考。

    C語言預處理器可剔除代碼注釋,但同時也會剔除#if0...#endif之類的無效語句,不滿足要求。于是,作者用UEStudio打開源文件,進入【搜索(Search)】|【替換(Replace)】頁,選擇Unix正則表達式引擎,用^\s*/\*.*\*/匹配單行注釋(/*abc*/)并替換為空字符,用^\s*//.*$匹配單行注釋(//abc)并替換為空字符。然后,查找并手工刪除跨行注釋及其他未匹配到的單行注釋。最后,選擇UltraEdit正則表達式引擎,用%[^t]++^p匹配空行并替換為空字符,即可刪除所有空行。注意,UEStudio幫助中提供的正則表達式^p$一次只能刪除一個空行。

    按上述方式處理兩個大型文件后,初步發現BCLineCounter.py關于有效代碼行數的統計是正確的。然而,這種半人工處理方式太過低效,因此作者想到讓兩個腳本處理相同的文件,并輸出有效代碼行或純注釋行的內容,將其通過AraxisMerge對比。該工具會高亮差異行,且人工檢查很容易鑒別正誤。此處,作者假定對于給定文件的給定類型行數,BCLineCounter.py和CLineCounter.py必有一者統計正確(可作基準)。當然,也有可能兩者均有誤差。因此,若求保險,也可同時輸出類型和行內容,再行對比。

    綜合檢查結果發現,BCLineCounter.py較CLineCounter.py更為健壯。這是因為,模式匹配需要處理的場景繁多,極易疏漏。例如,CLineCounter.py無法正確處理下面的代碼片段:

    voidtest(){

    /*/multiline,

    comment*/

    inta=1/2;//comment

    //*Assignavalue

    }

    讀者若有興趣,可修改和調試CLineCounter.py里的正則表達式,使該腳本高效而健壯。

    以上內容為大家介紹了Python性能分析,希望對大家有所幫助,如果想要了解更多Python相關知識,請關注IT培訓機構:千鋒教育。

    聲明:本站稿件版權均屬千鋒教育所有,未經許可不得擅自轉載。

    猜你喜歡LIKE

    python實現WSGI的框架

    2023-11-13

    python打開文本文件有哪些方法?

    2023-11-13

    python使用loguru操作日志

    2023-11-13

    最新文章NEW

    python-=是什么意思

    2023-11-13

    pythonre是什么?

    2023-11-13

    python列表追加元素出錯的解決

    2023-11-13

    相關推薦HOT

    更多>>

    快速通道 更多>>

    最新開班信息 更多>>

    網友熱搜 更多>>