鄭明秀
(西南民族大學(xué)計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院,四川 成都 610041)
Python是一個有條理且強(qiáng)大的面向?qū)ο蟮某绦蛟O(shè)計(jì)語言[1].目前進(jìn)入TIOBE世界編程語言排行榜前三名[2].Python正變得越來越普遍,它已經(jīng)是各高校對于需要編程的所有科目的第一選擇,并且現(xiàn)在也得到了工業(yè)世界的青睞.它的可擴(kuò)展性,可嵌入性,豐富的庫等特點(diǎn),使其廣泛應(yīng)用于系統(tǒng)維護(hù)、圖形處理、數(shù)據(jù)分析,文本處理,數(shù)據(jù)庫編程,網(wǎng)絡(luò)編程,機(jī)器學(xué)習(xí),人工智能等方面[3-7].
Python具有高度的表現(xiàn)力且容易上手,其核心運(yùn)行于一組非常優(yōu)化的指令上,編程人員無需考慮底層計(jì)算元素,而專注于算法實(shí)現(xiàn),這使得高度抽象化的軟件在高度復(fù)雜化的硬件平臺上較低的執(zhí)行效率[8-11],其巨大的性能代價包括:Python虛擬機(jī)抽象讓矢量操作不能直接可用,還影響了保存L1/L2緩存中相關(guān)數(shù)據(jù)的優(yōu)化,最本質(zhì)的因素是其動態(tài)類型以及并不是一門編譯性的語言[12].其性能代價已成為業(yè)界的最大詬病,但是它能快速實(shí)現(xiàn)原型,若能根據(jù)操作對象做適當(dāng)?shù)拇a優(yōu)化,則能大幅提高代碼運(yùn)行效率.
Python應(yīng)用于各領(lǐng)域,其中有大量的信息處理,信息處理中對字符串的處理占很高的比例,本文針對字符串操作方法性能作實(shí)驗(yàn)對比研究.
Python是一種動態(tài)類型語言,采用基于值的內(nèi)存管理機(jī)制,變量中并不直接存放值,而是存放值的引用[13-14].在程序執(zhí)行過程中,變量名被綁定到不同的值,賦值運(yùn)算符只是創(chuàng)建變量名稱和值之間的關(guān)聯(lián).每個值都有自己的類型,但是變量名稱是沒有類型的,執(zhí)行過程中,一個變量名可以綁定任意類型的值[15].
Python有兩種共存的內(nèi)存管理機(jī)制:引用計(jì)數(shù)和垃圾回收.引用計(jì)數(shù)是一種非常高效的內(nèi)存管理手段,當(dāng)一個Python對象被引用時其引用計(jì)數(shù)增加1,當(dāng)其不再被某變量引用時則計(jì)數(shù)減1,當(dāng)引用計(jì)數(shù)等于0時對象被垃圾回收器刪除.
字符串是Python中不可變序列,不能直接對字符串對象進(jìn)行元素的增刪改操作.因此對字符串的增刪改操作都將產(chǎn)生一個新的字符串,即在內(nèi)存中重新分配內(nèi)存空間并進(jìn)行復(fù)制操作.
實(shí)際場景中對字符串的操作需求紛繁復(fù)雜,可能包含字符串的索引、切片、拼接、復(fù)制、搜索、統(tǒng)計(jì)、修改等等,為便于獲取實(shí)驗(yàn)對比數(shù)據(jù):
a)本實(shí)驗(yàn)僅研究字符串的拼接效率;
b)為簡化實(shí)驗(yàn),拼接對象假定為一個簡單的短字符串;
c)實(shí)驗(yàn)研究三種字符串拼接方式:+運(yùn)算符,join()函數(shù)以及推導(dǎo)式應(yīng)用
實(shí)驗(yàn)中需要處理時間,time庫是python提供的處理時間的標(biāo)準(zhǔn)庫,它提供系統(tǒng)級精確計(jì)時器的計(jì)時功能,可以用來分析程序的性能.本實(shí)驗(yàn)中僅需要使用其time()函數(shù)獲得程序運(yùn)行起始時刻和終止時刻,從而取得程序的運(yùn)行時間.
使用如下代碼計(jì)算連接運(yùn)算符+的運(yùn)算時間:
join()函數(shù)拼接字符串時需要生成列表,采用append()函數(shù)生成列表后使用join()連接字符串的代碼如下:
采用列表推導(dǎo)式生成列表,再使用join()函數(shù)連接字符串的代碼如下:
為了保證實(shí)驗(yàn)結(jié)果的穩(wěn)定性,避免因計(jì)算機(jī)內(nèi)隨機(jī)因素導(dǎo)致的測試誤差偏移過大,代碼中的n值取1000000~100000000.
本實(shí)驗(yàn)在如下約束條件下進(jìn)行:
·編程工具:Pycharm;
·解釋器版本:python 3.7.0
·測試數(shù)據(jù)
√數(shù)據(jù)屬性:字符串;
√數(shù)據(jù)規(guī)模:1000000~10000000;
√數(shù)據(jù)組數(shù):10?10組,即10個不同規(guī)模的數(shù)據(jù)組,每個不同規(guī)模的數(shù)據(jù)各自10組;
·實(shí)驗(yàn)環(huán)境
√OS:windows8.1中文版;
√處理器:Intel(R)CoreTMi7 4710MQ@2.50GHz 2.50GHz
√RAM:8G
√系統(tǒng)類型:64位操作系統(tǒng),基于x64的處理器
實(shí)驗(yàn)是由代碼運(yùn)行的起始時刻點(diǎn)與終止時刻之差表示代碼運(yùn)行的時間,系統(tǒng)中其它程序?qū)PU的占用將對實(shí)驗(yàn)結(jié)果產(chǎn)生較大的影響,因此實(shí)驗(yàn)開始前盡量關(guān)閉其它應(yīng)用軟件,降低計(jì)算機(jī)內(nèi)部隨機(jī)因素對實(shí)驗(yàn)結(jié)果可靠性的影響.另外需要多次實(shí)驗(yàn)采集實(shí)驗(yàn)數(shù)據(jù)樣本,以提高實(shí)驗(yàn)結(jié)果的可信度.此研究對字符串連接進(jìn)行了10次百萬次級到千萬次級運(yùn)行時間的數(shù)據(jù)采集.
為避免實(shí)驗(yàn)受隨機(jī)因素影響,上述實(shí)驗(yàn)共進(jìn)行10次,下面從三個角度展示實(shí)驗(yàn)數(shù)據(jù).表1是其中一次一百萬次級到一千萬次級字符串連接,三種連接方式的運(yùn)行時間數(shù)據(jù)樣本.數(shù)據(jù)顯示連接運(yùn)算符“+”需要的運(yùn)行時間明顯高于另外兩種連接方式.
表1 三種連接方式的運(yùn)行時間Table 1 Running time of three connection modes
表2是各種規(guī)模數(shù)據(jù)10次實(shí)驗(yàn)運(yùn)行時間均值.表2于表1數(shù)據(jù)對照,可以看出同等數(shù)據(jù)規(guī)模的單次實(shí)驗(yàn)數(shù)據(jù)與均值之間差距不大.表3是數(shù)據(jù)規(guī)模500萬次級的10次實(shí)驗(yàn)數(shù)據(jù),可以看出10次同等數(shù)據(jù)規(guī)模的三種不同連接方式的自身的運(yùn)行時間相近.因此可以認(rèn)為本次實(shí)驗(yàn)數(shù)據(jù)樣本是可信的.
表2 10次實(shí)驗(yàn)數(shù)據(jù)均值Table 2 Mean value of 10 times experiment
表3 數(shù)據(jù)規(guī)模5000000時運(yùn)行時間Table 3 Running time of data size is 5 millions
圖1和圖2是對表2數(shù)據(jù)的可視化展示,可以看出連接運(yùn)算符+隨著數(shù)據(jù)規(guī)模的增長,其運(yùn)行時間增長趨勢是非常明顯的,其圖形顯示不是線性關(guān)系,而是某種指數(shù)關(guān)系.由于連接運(yùn)算符+所用運(yùn)行時間遠(yuǎn)遠(yuǎn)大于另兩種連接方式,因此圖1中看不出join方法和推導(dǎo)式&join方法連接方式的趨勢,這兩種方式的運(yùn)行時間對于連接運(yùn)算符而言微乎其微.
圖2是join()方法和推導(dǎo)式&join()方法運(yùn)行時間的對比圖,圖形顯示這兩種連接方式使用推導(dǎo)式產(chǎn)生字符串列表后進(jìn)行字符串連接的運(yùn)行時間明顯更少,兩種連接方式運(yùn)行時間均伴隨數(shù)據(jù)規(guī)模的增長呈線性趨勢.
圖1 三種連接方式運(yùn)行時間曲線圖Fig.1 Curves of running time of three connections
圖2 Join方法與推導(dǎo)式&join方法對比圖Fig.2 Comparison between join()and derived&join()
本實(shí)驗(yàn)通過對三種不同連接方式的百萬次級到千萬次級數(shù)據(jù)規(guī)模的代碼多次運(yùn)行時間采樣,從采樣樣本觀察分析可知連接運(yùn)算符“+”的代碼運(yùn)行效率極低,隨著數(shù)據(jù)規(guī)模的增長,其運(yùn)行時間呈指數(shù)級增長;join()方法連接字符串的運(yùn)行時間遠(yuǎn)遠(yuǎn)優(yōu)于使用“+”運(yùn)算符連接字符串,對于大規(guī)模數(shù)據(jù)情況,join()方法的時間較“+”運(yùn)算符,其耗時微乎其微.當(dāng)推導(dǎo)式配合join()方法后,運(yùn)行時間再次明顯下降.
鑒于Python在如今大數(shù)據(jù)時代的流行趨勢,這次實(shí)驗(yàn)研究對于使用Python作為大數(shù)據(jù)處理工具的代碼優(yōu)化具有一定的指導(dǎo)意義.