Python:用pyinstrument做效能分析

orion發表於2022-03-21

導引

在計算密集型計算或一些Web應用中,我們常常需要對程式碼做效能分析。在Python中,最原始的方法即是使用time包中的time函式(該函式以秒為計時單位):

from time import sleep, time

def func1():
    sleep(0.001)

def func2():
    sleep(2)
    
begin1 = time()
func1()
end1 = time()


begin2 = time()
func2()
end2 = time()
print("func1 consume: %f, func2 consume:%f, func3 consume: %f"\
    % (end1-begin1, end2-begin2, end2-begin1))

控制檯輸出如下:

func1 consume: 0.001271, func2 consume:2.000421, func3 consume: 2.001692

pyinstrument基本用法

但是一旦函式多了起來,這種方式顯然過於繁雜。類似C語言中的cProfile,在Python中,也有專門的效能分析工具pyinstrument(該庫非內建,需要使用conda/pip安裝),我們在複雜的專案中可以使用它來代替簡陋的time.time()

首先來看一下基本的使用,它的使用框架如下:

from pyinstrument import Profiler
from time import sleep

def func1():
    sleep(0.1)

def func2():
    sleep(2)

profiler = Profiler()
profiler.start()

# 這裡是你要分析的程式碼,我們這裡分析func1和func2兩個函式
func1()
func2()

profiler.stop()

profiler.print()

可以看到,該工具也將其成功分析出了個函式的執行時間,併為我們標紅指出了執行2s的func2函式是效能瓶頸:

NLP多工學習

如果我們進一步調低函式的執行時間:

def func3():
    sleep(0.0001)

profiler = Profiler()
profiler.start()

func3()

profiler.stop()

profiler.print()

此時會顯示“No samples were recorded”,如下:
NLP多工學習

這是因為你的程式碼執行時間小於了1ms,如果你仍然想分析這段程式碼,你可以選擇將間隔值調到比預設的0.001(1ms)小,比如這樣:

profiler = Profiler(interval=0.0001)

此時你會發現,func3也能被檢測出來了:

NLP多工學習

此外,如果你要在瀏覽器中檢視分析結果,可以使用profiler.open_in_browser()代替profiler.print()的控制檯列印輸出:

NLP多工學習

也可以使用profiler.output_html()將profile以html形式輸出。

分析Flask中的web響應效能

我們也可以對Flask應用進行效能分析,具體的用法如下:

from flask import Flask, g, make_response, request
app = Flask(__name__)

@app.before_request
def before_request():
    if "profile" in request.args:
        g.profiler = Profiler()
        g.profiler.start()


@app.after_request
def after_request(response):
    if not hasattr(g, "profiler"):
        return response
    g.profiler.stop()
    output_html = g.profiler.output_html()
    return make_response(output_html)

這樣程式會檢測每個request中的?profile引數,如果檢測到則會開始分析。在執行了profiler的request結束後,它會生成一個html輸出替代掉真實的response並返回。

參考

相關文章