python matplotlib - 你如何描述腳本?




performance profiling time-complexity (19)

還有一個名為statprof的統計分析器。 它是一個採樣分析器,因此它為您的代碼增加了最小的開銷,並且提供了基於行的(而不僅僅是基於函數的)時序。 它更適合於像遊戲這樣的軟實時應用程序,但可能比cProfile的精度要低。

statprofstatprof ,所以可以通過指定git存儲庫來使用pip進行安裝:

pip install git+git://github.com/bos/[email protected]

你可以像這樣運行它:

import statprof

with statprof.profile():
    my_questionable_function()

另請參閱https://stackoverflow.com/a/10333592/320036

歐拉項目和其他編碼競賽往往有最大的時間來運行,或者人們吹噓他們的特定解決方案的運行速度。 使用python,有時候這些方法有點奇怪 - 即將時序代碼添加到__main__

什麼是一個好的方法來分析一個python程序需要運行多久?


@ Maxy對這個答案的評論幫了我很大的印象,我認為它應該有自己的答案:我已經有了cProfile生成的.pstats文件,我不想用pycallgraph重新運行,所以我使用了gprof2dot , svgs:

$ sudo apt-get install graphviz
$ git clone https://github.com/jrfonseca/gprof2dot
$ ln -s "$PWD"/gprof2dot/gprof2dot.py ~/bin
$ cd $PROJECT_DIR
$ gprof2dot.py -f pstats profile.pstats | dot -Tsvg -o callgraph.svg

和BLAM!

它使用點(與pycallgraph使用的一樣),所以輸出看起來很相似。 我認為gprof2dot丟失的信息較少:


這取決於你想從分析中看到什麼。 簡單的時間度量可以由(bash)給出。

time python python_prog.py

即使'/ usr / bin / time'也可以使用'--verbose'標誌輸出詳細的指標。

為了檢查每個函數給出的時間度量,並且為了更好地理解在函數上花費了多少時間,可以在python中使用內置的cProfile。

進入更詳細的指標如性能,時間不是唯一的指標。 你可以擔心內存,線程等。
分析選項:
1. line_profiler是另一個通常用於逐行查找時間指標的分析器。
2. memory_profiler是一種分析內存使用情況的工具。
3. heapy(來自Guppy項目)剖析堆中對象的使用方式。

這些是我傾向於使用的一些常見問題。 但如果你想了解更多信息,請閱讀bookbook是一本關於開始考慮性能的相當不錯的書。 您可以轉到有關使用Cython和JIT(Just-in-time)編譯的python的高級主題。


在Virtaal的source有一個非常有用的類和裝飾器,可以使分析(即使是特定的方法/函數)非常簡單。 然後可以在KCacheGrind中非常舒適地查看輸出。


pycallgraph時間我做了pycallgraph ,它可以從你的Python代碼生成一個可視化文件。 編輯:我已經更新了示例以使用最新版本。

pip install pycallgraph並安裝GraphViz您可以從命令行運行它:

pycallgraph graphviz -- ./mypythonscript.py

或者,您可以配置代碼的特定部分:

from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

with PyCallGraph(output=GraphvizOutput()):
    code_to_profile()

這些都會生成一個pycallgraph.png文件,類似於下面的圖片:


想知道python腳本正在做什麼? 進入Inspect Shell。 Inspect Shell允許您在不中斷運行腳本的情況下打印/更改全局變量並運行函數。 現在具有自動完成和命令歷史記錄(僅在Linux上)。

Inspect Shell不是一個pdb樣式的調試器。

https://github.com/amoffat/Inspect-Shell

你可以使用那個(和你的手錶)。


我認為cProfile非常適合分析,而kcachegrind非常適合可視化結果。 pyprof2calltree處理文件轉換。

python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree

要安裝所需的工具(至少在Ubuntu上):

apt-get install kcachegrind
pip install pyprof2calltree

結果:


Python包含一個名為cProfile的分析器。 它不僅提供了總運行時間,而且還分別計算每個函數的時間,並告訴您每個函數被調用的次數,從而可以輕鬆確定應該在哪裡進行優化。

你可以在代碼中或者從解釋器中調用它,如下所示:

import cProfile
cProfile.run('foo()')

更有用的是,您可以在運行腳本時調用cProfile:

python -m cProfile myscript.py

為了使它更容易,我創建了一個名為'profile.bat'的小批處理文件:

python -m cProfile %1

所以我所要做的就是運行:

profile euler048.py

我得到這個:

1007 function calls in 0.061 CPU seconds

Ordered by: standard name
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.061    0.061 <string>:1(<module>)
 1000    0.051    0.000    0.051    0.000 euler048.py:2(<lambda>)
    1    0.005    0.005    0.061    0.061 euler048.py:2(<module>)
    1    0.000    0.000    0.061    0.061 {execfile}
    1    0.002    0.002    0.053    0.053 {map}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler objects}
    1    0.000    0.000    0.000    0.000 {range}
    1    0.003    0.003    0.003    0.003 {sum}

編輯:從PyCon 2013更新了一個很好的視頻資源的鏈接,標題為Python分析


pprofile

line_profiler (這裡已經介紹過)也啟發了pprofile ,它被描述為:

行粒度,線程感知確定性和統計純python分析器

它提供line_profiler行粒度,是純Python,可以用作獨立命令或模塊,甚至可以生成可通過[k|q]cachegrind輕鬆分析的callgrind格式文件。

vprof

還有一個vprof ,一個Python包,描述如下:

為各種Python程序特性(如運行時間和內存使用情況)提供豐富且交互式的可視化。


另外值得一提的是GUI cProfile轉儲查看器RunSnakeRun 。 它允許您排序和選擇,從而放大程序的相關部分。 圖片中矩形的大小與所花費的時間成正比。 如果將鼠標懸停在矩形上,則會突出顯示表格中以及地圖上每個地方的呼叫。 當你雙擊一個矩形時,它會放大該部分。 它會告訴你誰調用了那部分以及那部分調用的內容。

描述性信息非常有幫助。 它向您顯示該位的代碼,這在處理內置庫調用時可能很有用。 它會告訴你什麼文件和哪一行可以找到代碼。

還想指出,OP說'分析',但他表示他的意思是'時間'。 請記住,在分析時程序運行速度會變慢。


一個處理Python分析的新工具是PyVmMonitor: http://www.pyvmmonitor.com/ ://www.pyvmmonitor.com/

它有一些獨特的功能,如

  • 將分析器附加到正在運行的(CPython)程序
  • 按需分析與Yappi整合
  • 在不同機器上的配置文件
  • 多進程支持(多處理,Django ...)
  • 實時採樣/ CPU視圖(帶時間範圍選擇)
  • 通過cProfile / profile集成進行確定性分析
  • 分析現有的PStats結果
  • 打開DOT文件
  • 程序化API訪問
  • 按方法或行分組樣本
  • PyDev集成
  • PyCharm集成

注意:它是商業的,但對開源免費。


值得指出的是,使用分析器只能在主線程上工作(默認情況下),並且如果使用它們,則不會從其他線程獲取任何信息。 這可能是一個小問題,因為它在profiler文檔中完全沒有提到。

如果您還想要配置線程,您需要查看文檔中的threading.setprofile()函數

你也可以創建自己的threading.Thread子類來完成它:

class ProfiledThread(threading.Thread):
    # Overrides threading.Thread.run()
    def run(self):
        profiler = cProfile.Profile()
        try:
            return profiler.runcall(threading.Thread.run, self)
        finally:
            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

並使用ProfiledThread類而不是標準類。 它可能會給你更多的靈活性,但我不確定它是否值得,尤其是如果你使用的第三方代碼不會使用你的類。


當我不在服務器上的根目錄時,我使用lsprofcalltree.py並像這樣運行我的程序:

python lsprofcalltree.py -o callgrind.1 test.py

然後我可以用任何與callgrind兼容的軟件打開報告,例如qcachegrind


cProfile非常適合快速剖析,但大多數情況下它都會以錯誤結尾。 函數runctx通過正確地初始化環境和變量來解決這個問題,希望它對於某人有用:

import cProfile
cProfile.runctx('foo()', None, locals())

有很多很棒的答案,但是他們或者使用命令行或者一些外部程序來分析和/或排序結果。

我真的錯過了一些我可以在我的IDE(eclipse-PyDev)中使用的方式,而無需觸摸命令行或安裝任何東西。 所以在這裡。

無命令行分析

def count():
    from math import sqrt
    for x in range(10**5):
        sqrt(x)

if __name__ == '__main__':
    import cProfile, pstats
    cProfile.run("count()", "{}.profile".format(__file__))
    s = pstats.Stats("{}.profile".format(__file__))
    s.strip_dirs()
    s.sort_stats("time").print_stats(10)

有關更多信息,請參閱文檔或其他答案。



根據Joe Shaw關於多線程代碼不能按預期工作的回答,我認為runcall中的runcall方法僅僅是圍繞profiled函數調用進行self.enable()self.disable()調用,所以你可以簡單地做到這一點你自己並擁有你想要的任何代碼,而對現有代碼的干擾最小。


我的方法是使用yappi( https://code.google.com/p/yappi/ )。 與RPC服務器結合使用(甚至只是為了調試),您可以註冊方法來啟動,停止和打印分析信息,例如以這種方式:

@staticmethod
def startProfiler():
    yappi.start()

@staticmethod
def stopProfiler():
    yappi.stop()

@staticmethod
def printProfiler():
    stats = yappi.get_stats(yappi.SORTTYPE_TTOT, yappi.SORTORDER_DESC, 20)
    statPrint = '\n'
    namesArr = [len(str(stat[0])) for stat in stats.func_stats]
    log.debug("namesArr %s", str(namesArr))
    maxNameLen = max(namesArr)
    log.debug("maxNameLen: %s", maxNameLen)

    for stat in stats.func_stats:
        nameAppendSpaces = [' ' for i in range(maxNameLen - len(stat[0]))]
        log.debug('nameAppendSpaces: %s', nameAppendSpaces)
        blankSpace = ''
        for space in nameAppendSpaces:
            blankSpace += space

        log.debug("adding spaces: %s", len(nameAppendSpaces))
        statPrint = statPrint + str(stat[0]) + blankSpace + " " + str(stat[1]).ljust(8) + "\t" + str(
            round(stat[2], 2)).ljust(8 - len(str(stat[2]))) + "\t" + str(round(stat[3], 2)) + "\n"

    log.log(1000, "\nname" + ''.ljust(maxNameLen - 4) + " ncall \tttot \ttsub")
    log.log(1000, statPrint)

然後,當你的程序工作時,你可以通過調用startProfiler RPC方法並通過調用printProfiler (或者修改rpc方法將它返回給調用者)將日誌文件信息轉儲到日誌文件來隨時啟動分析器,並獲得如下輸出:

2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
name                                                                                                                                      ncall     ttot    tsub
2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
C:\Python27\lib\sched.py.run:80                                                                                                           22        0.11    0.05
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293                                                22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515                                                    22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66                                       1         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.date_time_string:464                                                                                    1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py._get_raw_meminfo:243     4         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537                                                                          1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py.get_system_cpu_times:148 4         0.0     0.0
<string>.__new__:8                                                                                                                        220       0.0     0.0
C:\Python27\lib\socket.py.close:276                                                                                                       4         0.0     0.0
C:\Python27\lib\threading.py.__init__:558                                                                                                 1         0.0     0.0
<string>.__new__:8                                                                                                                        4         0.0     0.0
C:\Python27\lib\threading.py.notify:372                                                                                                   1         0.0     0.0
C:\Python27\lib\rfc822.py.getheader:285                                                                                                   4         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301                                                                                  1         0.0     0.0
C:\Python27\lib\xmlrpclib.py.end:816                                                                                                      3         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467                                                                                         1         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460                                                                               1         0.0     0.0
C:\Python27\lib\SocketServer.py.close_request:475                                                                                         1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\__init__.py.cpu_times:1066               4         0.0     0.0 

對於短腳本來說它可能不是很有用,但有助於優化服務器類型的進程,特別是考慮到printProfiler方法可以隨時調用多次來分析和比較不同的程序使用場景。


這是我注意到沒人提到的。

將所有可用的處理器分配給模擬器

這是你可以嘗試的。 它確實為我加速了模擬器,特別是在加載時。 我注意到模擬器只使用可用CPU的單核。 我將其設置為使用所有可用的處理器。

我正在使用Windows 7。

當Android模擬器啟動時,打開任務管理器,在Process選項卡下查找“emulator-arm.exe”或“emulator-arm.exe * 32”...右鍵單擊它,選擇Processor Affinity和為仿真器分配盡可能多的處理器。





python performance profiling time-complexity