真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

包含python檢測(cè)函數(shù)耗時(shí)的詞條

「干貨」讓Python性能起飛的15個(gè)技巧,你知道幾個(gè)呢?

前言

創(chuàng)新互聯(lián)公司2013年開(kāi)創(chuàng)至今,先為東寧等服務(wù)建站,東寧等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為東寧企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

Python 一直以來(lái)被大家所詬病的一點(diǎn)就是執(zhí)行速度慢,但不可否認(rèn)的是 Python 依然是我們學(xué)習(xí)和工作中的一大利器。本文總結(jié)了15個(gè)tips有助于提升 Python 執(zhí)行速度、優(yōu)化性能。

關(guān)于 Python 如何精確地測(cè)量程序的執(zhí)行時(shí)間,這個(gè)問(wèn)題看起來(lái)簡(jiǎn)單其實(shí)很復(fù)雜,因?yàn)槌绦虻膱?zhí)行時(shí)間受到很多因素的影響,例如操作系統(tǒng)、Python 版本以及相關(guān)硬件(CPU 性能、內(nèi)存讀寫(xiě)速度)等。在同一臺(tái)電腦上運(yùn)行相同版本的語(yǔ)言時(shí),上述因素就是確定的了,但是程序的睡眠時(shí)間依然是變化的,且電腦上正在運(yùn)行的其他程序也會(huì)對(duì)實(shí)驗(yàn)有干擾,因此嚴(yán)格來(lái)說(shuō)這就是實(shí)驗(yàn)不可重復(fù)。

我了解到的關(guān)于計(jì)時(shí)比較有代表性的兩個(gè)庫(kù)就是 time 和 timeit 。

其中, time 庫(kù)中有 time() 、 perf_counter() 以及 process_time() 三個(gè)函數(shù)可用來(lái)計(jì)時(shí)(以秒為單位),加后綴 _ns 表示以納秒計(jì)時(shí)(自 Python3.7 始)。在此之前還有 clock() 函數(shù),但是在 Python3.3 之后被移除了。上述三者的區(qū)別如下:

與 time 庫(kù)相比, timeit 有兩個(gè)優(yōu)點(diǎn):

timeit.timeit(stmt='pass', setup='pass', timer= , number=1000000, globals=None) 參數(shù)說(shuō)明:

本文所有的計(jì)時(shí)均采用 timeit 方法,且采用默認(rèn)的執(zhí)行次數(shù)一百萬(wàn)次。

為什么要執(zhí)行一百萬(wàn)次呢?因?yàn)槲覀兊臏y(cè)試程序很短,如果不執(zhí)行這么多次的話,根本看不出差距。

Exp1:將字符串?dāng)?shù)組中的小寫(xiě)字母轉(zhuǎn)為大寫(xiě)字母。

測(cè)試數(shù)組為 oldlist = ['life', 'is', 'short', 'i', 'choose', 'python']。

方法一

方法二

方法一耗時(shí) 0.5267724000000005s ,方法二耗時(shí) 0.41462569999999843s ,性能提升 21.29%

Exp2:求兩個(gè) list 的交集。

測(cè)試數(shù)組:a = [1,2,3,4,5],b = [2,4,6,8,10]。

方法一

方法二

方法一耗時(shí) 0.9507264000000006s ,方法二耗時(shí) 0.6148200999999993s ,性能提升 35.33%

關(guān)于 set() 的語(yǔ)法: | 、 、 - 分別表示求并集、交集、差集。

我們可以通過(guò)多種方式對(duì)序列進(jìn)行排序,但其實(shí)自己編寫(xiě)排序算法的方法有些得不償失。因?yàn)閮?nèi)置的 sort() 或 sorted() 方法已經(jīng)足夠優(yōu)秀了,且利用參數(shù) key 可以實(shí)現(xiàn)不同的功能,非常靈活。二者的區(qū)別是 sort() 方法僅被定義在 list 中,而 sorted() 是全局方法對(duì)所有的可迭代序列都有效。

Exp3:分別使用快排和 sort() 方法對(duì)同一列表排序。

測(cè)試數(shù)組:lists = [2,1,4,3,0]。

方法一

方法二

方法一耗時(shí) 2.4796975000000003s ,方法二耗時(shí) 0.05551999999999424s ,性能提升 97.76%

順帶一提, sorted() 方法耗時(shí) 0.1339823999987857s 。

可以看出, sort() 作為 list 專(zhuān)屬的排序方法還是很強(qiáng)的, sorted() 雖然比前者慢一點(diǎn),但是勝在它“不挑食”,它對(duì)所有的可迭代序列都有效。

擴(kuò)展 :如何定義 sort() 或 sorted() 方法的 key

1.通過(guò) lambda 定義

2.通過(guò) operator 定義

operator 的 itemgetter() 適用于普通數(shù)組排序, attrgetter() 適用于對(duì)象數(shù)組排序

3.通過(guò) cmp_to_key() 定義,最為靈活

Exp4:統(tǒng)計(jì)字符串中每個(gè)字符出現(xiàn)的次數(shù)。

測(cè)試數(shù)組:sentence='life is short, i choose python'。

方法一

方法二

方法一耗時(shí) 2.8105250000000055s ,方法二耗時(shí) 1.6317423000000062s ,性能提升 41.94%

列表推導(dǎo)(list comprehension)短小精悍。在小代碼片段中,可能沒(méi)有太大的區(qū)別。但是在大型開(kāi)發(fā)中,它可以節(jié)省一些時(shí)間。

Exp5:對(duì)列表中的奇數(shù)求平方,偶數(shù)不變。

測(cè)試數(shù)組:oldlist = range(10)。

方法一

方法二

方法一耗時(shí) 1.5342976000000021s ,方法二耗時(shí) 1.4181957999999923s ,性能提升 7.57%

大多數(shù)人都習(xí)慣使用 + 來(lái)連接字符串。但其實(shí),這種方法非常低效。因?yàn)椋? + 操作在每一步中都會(huì)創(chuàng)建一個(gè)新字符串并復(fù)制舊字符串。更好的方法是用 join() 來(lái)連接字符串。關(guān)于字符串的其他操作,也盡量使用內(nèi)置函數(shù),如 isalpha() 、 isdigit() 、 startswith() 、 endswith() 等。

Exp6:將字符串列表中的元素連接起來(lái)。

測(cè)試數(shù)組:oldlist = ['life', 'is', 'short', 'i', 'choose', 'python']。

方法一

方法二

方法一耗時(shí) 0.27489080000000854s ,方法二耗時(shí) 0.08166570000000206s ,性能提升 70.29%

join 還有一個(gè)非常舒服的點(diǎn),就是它可以指定連接的分隔符,舉個(gè)例子

life//is//short//i//choose//python

Exp6:交換x,y的值。

測(cè)試數(shù)據(jù):x, y = 100, 200。

方法一

方法二

方法一耗時(shí) 0.027853900000010867s ,方法二耗時(shí) 0.02398730000000171s ,性能提升 13.88%

在不知道確切的循環(huán)次數(shù)時(shí),常規(guī)方法是使用 while True 進(jìn)行無(wú)限循環(huán),在代碼塊中判斷是否滿足循環(huán)終止條件。雖然這樣做沒(méi)有任何問(wèn)題,但 while 1 的執(zhí)行速度比 while True 更快。因?yàn)樗且环N數(shù)值轉(zhuǎn)換,可以更快地生成輸出。

Exp8:分別用 while 1 和 while True 循環(huán) 100 次。

方法一

方法二

方法一耗時(shí) 3.679268300000004s ,方法二耗時(shí) 3.607847499999991s ,性能提升 1.94%

將文件存儲(chǔ)在高速緩存中有助于快速恢復(fù)功能。Python 支持裝飾器緩存,該緩存在內(nèi)存中維護(hù)特定類(lèi)型的緩存,以實(shí)現(xiàn)最佳軟件驅(qū)動(dòng)速度。我們使用 lru_cache 裝飾器來(lái)為斐波那契函數(shù)提供緩存功能,在使用 fibonacci 遞歸函數(shù)時(shí),存在大量的重復(fù)計(jì)算,例如 fibonacci(1) 、 fibonacci(2) 就運(yùn)行了很多次。而在使用了 lru_cache 后,所有的重復(fù)計(jì)算只會(huì)執(zhí)行一次,從而大大提高程序的執(zhí)行效率。

Exp9:求斐波那契數(shù)列。

測(cè)試數(shù)據(jù):fibonacci(7)。

方法一

方法二

方法一耗時(shí) 3.955014900000009s ,方法二耗時(shí) 0.05077979999998661s ,性能提升 98.72%

注意事項(xiàng):

我被執(zhí)行了(執(zhí)行了兩次 demo(1, 2) ,卻只輸出一次)

functools.lru_cache(maxsize=128, typed=False) 的兩個(gè)可選參數(shù):

點(diǎn)運(yùn)算符( . )用來(lái)訪問(wèn)對(duì)象的屬性或方法,這會(huì)引起程序使用 __getattribute__() 和 __getattr__() 進(jìn)行字典查找,從而帶來(lái)不必要的開(kāi)銷(xiāo)。尤其注意,在循環(huán)當(dāng)中,更要減少點(diǎn)運(yùn)算符的使用,應(yīng)該將它移到循環(huán)外處理。

這啟發(fā)我們應(yīng)該盡量使用 from ... import ... 這種方式來(lái)導(dǎo)包,而不是在需要使用某方法時(shí)通過(guò)點(diǎn)運(yùn)算符來(lái)獲取。其實(shí)不光是點(diǎn)運(yùn)算符,其他很多不必要的運(yùn)算我們都盡量移到循環(huán)外處理。

Exp10:將字符串?dāng)?shù)組中的小寫(xiě)字母轉(zhuǎn)為大寫(xiě)字母。

測(cè)試數(shù)組為 oldlist = ['life', 'is', 'short', 'i', 'choose', 'python']。

方法一

方法二

方法一耗時(shí) 0.7235491999999795s ,方法二耗時(shí) 0.5475435999999831s ,性能提升 24.33%

當(dāng)我們知道具體要循環(huán)多少次時(shí),使用 for 循環(huán)比使用 while 循環(huán)更好。

Exp12:使用 for 和 while 分別循環(huán) 100 次。

方法一

方法二

方法一耗時(shí) 3.894683299999997s ,方法二耗時(shí) 1.0198077999999953s ,性能提升 73.82%

Numba 可以將 Python 函數(shù)編譯碼為機(jī)器碼執(zhí)行,大大提高代碼執(zhí)行速度,甚至可以接近 C 或 FORTRAN 的速度。它能和 Numpy 配合使用,在 for 循環(huán)中或存在大量計(jì)算時(shí)能顯著地提高執(zhí)行效率。

Exp12:求從 1 加到 100 的和。

方法一

方法二

方法一耗時(shí) 3.7199997000000167s ,方法二耗時(shí) 0.23769430000001535s ,性能提升 93.61%

矢量化是 NumPy 中的一種強(qiáng)大功能,可以將操作表達(dá)為在整個(gè)數(shù)組上而不是在各個(gè)元素上發(fā)生。這種用數(shù)組表達(dá)式替換顯式循環(huán)的做法通常稱(chēng)為矢量化。

在 Python 中循環(huán)數(shù)組或任何數(shù)據(jù)結(jié)構(gòu)時(shí),會(huì)涉及很多開(kāi)銷(xiāo)。NumPy 中的向量化操作將內(nèi)部循環(huán)委托給高度優(yōu)化的 C 和 Fortran 函數(shù),從而使 Python 代碼更加快速。

Exp13:兩個(gè)長(zhǎng)度相同的序列逐元素相乘。

測(cè)試數(shù)組:a = [1,2,3,4,5], b = [2,4,6,8,10]

方法一

方法二

方法一耗時(shí) 0.6706845000000214s ,方法二耗時(shí) 0.3070132000000001s ,性能提升 54.22%

若要檢查列表中是否包含某成員,通常使用 in 關(guān)鍵字更快。

Exp14:檢查列表中是否包含某成員。

測(cè)試數(shù)組:lists = ['life', 'is', 'short', 'i', 'choose', 'python']

方法一

方法二

方法一耗時(shí) 0.16038449999999216s ,方法二耗時(shí) 0.04139250000000061s ,性能提升 74.19%

itertools 是用來(lái)操作迭代器的一個(gè)模塊,其函數(shù)主要可以分為三類(lèi):無(wú)限迭代器、有限迭代器、組合迭代器。

Exp15:返回列表的全排列。

測(cè)試數(shù)組:["Alice", "Bob", "Carol"]

方法一

方法二

方法一耗時(shí) 3.867292899999484s ,方法二耗時(shí) 0.3875405000007959s ,性能提升 89.98%

根據(jù)上面的測(cè)試數(shù)據(jù),我繪制了下面這張實(shí)驗(yàn)結(jié)果圖,可以更加直觀的看出不同方法帶來(lái)的性能差異。

從圖中可以看出,大部分的技巧所帶來(lái)的性能增幅還是比較可觀的,但也有少部分技巧的增幅較?。ɡ缇幪?hào)5、7、8,其中,第 8 條的兩種方法幾乎沒(méi)有差異)。

總結(jié)下來(lái),我覺(jué)得其實(shí)就是下面這兩條原則:

內(nèi)置庫(kù)函數(shù)由專(zhuān)業(yè)的開(kāi)發(fā)人員編寫(xiě)并經(jīng)過(guò)了多次測(cè)試,很多庫(kù)函數(shù)的底層是用 C 語(yǔ)言開(kāi)發(fā)的。因此,這些函數(shù)總體來(lái)說(shuō)是非常高效的(比如 sort() 、 join() 等),自己編寫(xiě)的方法很難超越它們,還不如省省功夫,不要重復(fù)造輪子了,何況你造的輪子可能更差。所以,如果函數(shù)庫(kù)中已經(jīng)存在該函數(shù),就直接拿來(lái)用。

有很多優(yōu)秀的第三方庫(kù),它們的底層可能是用 C 和 Fortran 來(lái)實(shí)現(xiàn)的,像這樣的庫(kù)用起來(lái)絕對(duì)不會(huì)吃虧,比如前文提到的 Numpy 和 Numba,它們帶來(lái)的提升都是非常驚人的。類(lèi)似這樣的庫(kù)還有很多,比如Cython、PyPy等,這里我只是拋磚引玉。

原文鏈接:

python 打印出函數(shù)執(zhí)行所用時(shí)間

使用timeit模塊,先介紹下:

timeit 模塊

timeit?模塊定義了接受兩個(gè)參數(shù)的?Timer?類(lèi)。兩個(gè)參數(shù)都是字符串。 第一個(gè)參數(shù)是你要計(jì)時(shí)的語(yǔ)句或者函數(shù)。 傳遞給?Timer?的第二個(gè)參數(shù)是為第一個(gè)參數(shù)語(yǔ)句構(gòu)建環(huán)境的導(dǎo)入語(yǔ)句。 從內(nèi)部講,?timeit?構(gòu)建起一個(gè)獨(dú)立的虛擬環(huán)境, 手工地執(zhí)行建立語(yǔ)句,然后手工地編譯和執(zhí)行被計(jì)時(shí)語(yǔ)句。

一旦有了?Timer?對(duì)象,最簡(jiǎn)單的事就是調(diào)用?timeit(),它接受一個(gè)參數(shù)為每個(gè)測(cè)試中調(diào)用被計(jì)時(shí)語(yǔ)句的次數(shù),默認(rèn)為一百萬(wàn)次;返回所耗費(fèi)的秒數(shù)。

Timer?對(duì)象的另一個(gè)主要方法是?repeat(), 它接受兩個(gè)可選參數(shù)。 第一個(gè)參數(shù)是重復(fù)整個(gè)測(cè)試的次數(shù),第二個(gè)參數(shù)是每個(gè)測(cè)試中調(diào)用被計(jì)時(shí)語(yǔ)句的次數(shù)。 兩個(gè)參數(shù)都是可選的,它們的默認(rèn)值分別是?3?和?1000000。?repeat()?方法返回以秒記錄的每個(gè)測(cè)試循環(huán)的耗時(shí)列表。Python?有一個(gè)方便的?min?函數(shù)可以把輸入的列表返回成最小值,如: min(t.repeat(3, 1000000))

你可以在命令行使用?timeit?模塊來(lái)測(cè)試一個(gè)已存在的?Python?程序,而不需要修改代碼。

再給你個(gè)例子,你就知道怎么做了。

#?-*-?coding:?utf-8?-*-

#!/bin/env?python

def?test1():

n=0

for?i?in?range(101):

n+=i

return?n

def?test2():

return?sum(range(101))

def?test3():

return?sum(x?for?x?in?range(101))

if?__name__=='__main__':

from?timeit?import?Timer

t1=Timer("test1()","from?__main__?import?test1")

t2=Timer("test2()","from?__main__?import?test2")

t3=Timer("test3()","from?__main__?import?test3")

print?t1.timeit(1000000)

print?t2.timeit(1000000)

print?t3.timeit(1000000)

print?t1.repeat(3,1000000)

print?t2.repeat(3,1000000)

print?t3.repeat(3,1000000)

7種檢測(cè)Python程序運(yùn)行時(shí)間、CPU和內(nèi)存占用的方法

1. 使用裝飾器來(lái)衡量函數(shù)執(zhí)行時(shí)間

有一個(gè)簡(jiǎn)單方法,那就是定義一個(gè)裝飾器來(lái)測(cè)量函數(shù)的執(zhí)行時(shí)間,并輸出結(jié)果:

import time

from functoolsimport wraps

import random

def fn_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.__name__, str(t1- t0))

)

? return result

return function_timer

@fn_timer

def random_sort(n):

return sorted([random.random() for i in range(n)])

if __name__== "__main__":

random_sort(2000000)

輸出:Total time running random_sort: 0.6598007678985596 seconds

使用方式的話,就是在要監(jiān)控的函數(shù)定義上面加上 @fn_timer 就行了

或者

# 可監(jiān)控程序運(yùn)行時(shí)間

import time

import random

def clock(func):

def wrapper(*args, **kwargs):

? ? start_time= time.time()

? ? result= func(*args, **kwargs)

? ? end_time= time.time()

? ? print("共耗時(shí): %s秒" % round(end_time- start_time, 5))

? ? return result

return wrapper

@clock

def random_sort(n):

return sorted([random.random() for i in range(n)])

if __name__== "__main__":

random_sort(2000000)

輸出結(jié)果:共耗時(shí): 0.65634秒

2. 使用timeit模塊

另一種方法是使用timeit模塊,用來(lái)計(jì)算平均時(shí)間消耗。

執(zhí)行下面的腳本可以運(yùn)行該模塊。

這里的timing_functions是Python腳本文件名稱(chēng)。

在輸出的末尾,可以看到以下結(jié)果:4?loops, best of?5:?2.08?sec per loop

這表示測(cè)試了4次,平均每次測(cè)試重復(fù)5次,最好的測(cè)試結(jié)果是2.08秒。

如果不指定測(cè)試或重復(fù)次數(shù),默認(rèn)值為10次測(cè)試,每次重復(fù)5次。

3. 使用Unix系統(tǒng)中的time命令

然而,裝飾器和timeit都是基于Python的。在外部環(huán)境測(cè)試Python時(shí),unix time實(shí)用工具就非常有用。

運(yùn)行time實(shí)用工具:

輸出結(jié)果為:

Total?time running random_sort:?1.3931210041?seconds

real?1.49

user?1.40

sys?0.08

第一行來(lái)自預(yù)定義的裝飾器,其他三行為:

real表示的是執(zhí)行腳本的總時(shí)間

user表示的是執(zhí)行腳本消耗的CPU時(shí)間。

sys表示的是執(zhí)行內(nèi)核函數(shù)消耗的時(shí)間。

注意:根據(jù)維基百科的定義,內(nèi)核是一個(gè)計(jì)算機(jī)程序,用來(lái)管理軟件的輸入輸出,并將其翻譯成CPU和其他計(jì)算機(jī)中的電子設(shè)備能夠執(zhí)行的數(shù)據(jù)處理指令。

因此,Real執(zhí)行時(shí)間和User+Sys執(zhí)行時(shí)間的差就是消耗在輸入/輸出和系統(tǒng)執(zhí)行其他任務(wù)時(shí)消耗的時(shí)間。

4. 使用cProfile模塊

5. 使用line_profiler模塊

6. 使用memory_profiler模塊

7. 使用guppy包

找出python程序中運(yùn)行時(shí)最耗時(shí)間的部分

那就是profile和cProfile模塊:

import?cProfile

cProfile.run('function....')

另外,time模塊,在不同的函數(shù)的開(kāi)頭和結(jié)尾分別計(jì)時(shí),然后將兩個(gè)時(shí)間相減,就可以獲得這段函數(shù)的運(yùn)行時(shí)間了,然后在看哪段函數(shù)占的時(shí)間比較大:

import?time

t1=time.time()

##you?function?segment?here

t2=time.time()

timediff=t2-t1

在python里用time.time判斷函數(shù)的執(zhí)行時(shí)間靠譜嗎

time.time輸出的是時(shí)間戳, 時(shí)間戳是從1970年1月1號(hào)0點(diǎn)0分0秒開(kāi)始計(jì)時(shí)的,也就是就開(kāi)始計(jì)時(shí)到現(xiàn)在經(jīng)過(guò)了多少秒,這個(gè)值是不會(huì)重復(fù)的。


分享文章:包含python檢測(cè)函數(shù)耗時(shí)的詞條
當(dāng)前地址:http://weahome.cn/article/hgsipd.html

其他資訊

在線咨詢(xún)

微信咨詢(xún)

電話咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部