八月 22, 2009
» 簡單的 python timeit 範例

[更正啟事:此篇測試有誤,更正於]


PTT 文章回收 :)

要測微效能的差異,可考慮 python 內建(總是如此啊)更準確的 timeit 模組

使用方式如:


# encoding: utf8



import timeit



run_test1 = '''

import testit

testit.test1(testit.al, testit.bl)

'''

run_test2 = '''

import testit

testit.test2(testit.al, testit.bl)

'''

run_test3 = '''

import testit

testit.test3(testit.al, testit.bl)

'''



al = []

bl = []

for i in range(1000):

    al.append(i)

    bl.append(999 -i)



def test1(al, bl):

    al = al + bl



def test2(al, bl):

    al.extend(bl)



def test3(al, bl):

    al += bl



if __name__ == '__main__':

    times = 100000

    t1 = timeit.Timer(stmt=run_test1)

    print "%.8f sec/pass" % (t1.timeit(number=times)/times)



    t2 = timeit.Timer(stmt=run_test2)

    print "%.8f sec/pass" % (t2.timeit(number=times)/times)



    t3 = timeit.Timer(stmt=run_test3)

    print "%.8f sec/pass" % (t3.timeit(number=times)/times)



# See also: http://docs.python.org/library/timeit.html



附帶這個測試的 output 作為參考
0.00002528 sec/pass
0.00002075 sec/pass
0.00002029 sec/pass

PS. 就算這麼做,還是要跑第二次之後才比較接近實際上想看到的差異
第一次
% python testit.py
0.00002639 sec/pass
0.00002135 sec/pass
0.00002575 sec/pass

第二次
% python testit.py
0.00002557 sec/pass
0.00002103 sec/pass
0.00001995 sec/pass

第三次
% python testit.py
0.00002528 sec/pass
0.00002075 sec/pass
0.00002029 sec/pass

» 更正:簡單的 python timeit 範例

感謝 ptt python 板友 sbr 指正:

※ 引述《sbrhsieh (sbr)》...
: 依照上述的碼來說,依照 Python 2.5.4 內附的 timeit module 的設計來看,test2
: 與 test3 重複執行多次,會導致 testit module loaded 後 al 參考的 list object
: 一直作串接動作而變長(長度超過 100M)。
: 重複跑 test2 與 test3 會比 test1 多許多記憶體配置與 memory copy 的操作,
: 我不認為你跑出來的量測結果是合理的(test2/test3 應該比 test1 慢上許多)。

原文中的程式碼有如下問題:global is evil XD

先看看原來程式碼的問題,我們加上下面的程式碼:

run_print_len = '''
import sys
import testit
print >> sys.stderr, 'len(al):', len(testit.al), 'len(bl):', len(testit.bl)
'''

...(原來的code)

if __name__ == '__main__':
...(原來的code)

pl = timeit.Timer(run_print_len) # 新增這兩行
pl.timeit(number=1) #

得到

% python2.5 testit.py
0.00002924 sec/pass
0.00002564 sec/pass
0.00002465 sec/pass
len(al): 200001000 len(bl): 1000

可以看到 al list 的長度非常之長,都快跟我一樣長了 XD (誤),因為每次對 testit.al 所作的改變都會繼續被下一個 test 使用。這樣的測試造成 al 在每個 test 的長度都不同,可能造成測試的不準確。
如 sbr 所述,記憶體可能需要重新配置之類的 (不過在我的環境好像沒有影響?)

import timeit



run_test1 = '''

import testit

al, bl = testit.generate_albl()

al = testit.test1(al, bl)

'''

run_test2 = '''

import testit

al, bl = testit.generate_albl()

al = testit.test2(al, bl)

'''

run_test3 = '''

import testit

al, bl = testit.generate_albl()

al = testit.test3(al, bl)

'''



run_print_len = '''

import sys

import testit

al, bl = testit.generate_albl()

print >> sys.stderr, 'len(al):', len(al), 'len(bl):', len(bl)

'''



def generate_albl():

    al = [1]*1000

    bl = [999]*1000

    return al, bl



def test1(al, bl):

    al = al + bl

    return al



def test2(al, bl):

    al.extend(bl)

    return al



def test3(al, bl):

    al += bl

    return al



if __name__ == '__main__':

    times = 100000

    t1 = timeit.Timer(run_test1)

    print "%.8f sec/pass" % (t1.timeit(number=times)/times)



    t2 = timeit.Timer(run_test2)

    print "%.8f sec/pass" % (t2.timeit(number=times)/times)



    t3 = timeit.Timer(run_test3)

    print "%.8f sec/pass" % (t3.timeit(number=times)/times)



    pl = timeit.Timer(run_print_len)

    pl.timeit(number=1)

修正後的結果:
Python 2.5.4 (r254:67917, Dec 23 2008, 14:57:27) 
[GCC 4.0.1 (Apple Computer, Inc. build 5363)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

% python2.5 testit.py
0.00005440 sec/pass
0.00004385 sec/pass
0.00004388 sec/pass
len(al): 1000 len(bl): 1000

八月 16, 2009
» COSCUP 2009 Lighting Talk 補遺 - 關於軟體開發的敏捷測試

開源人年會2009雖然只是五分鐘,但還是緊張了一下,有些話說得不清楚或亂七八糟,在此望請海涵。

不過聽到聽眾的笑聲還是很開心。雖然很多梗沒講到(測試網頁是否被反山達基),反而跑出一些莫明奇妙的點(對啊)。其它的 Lighting Talks 更是歡樂無比,能一邊跑步一邊講真的是,XD。

先在這裡補一下沒講到的點:

一修改完檔案立刻看到測試結果,概念上說來非常簡單:

檔案有更動->立刻進行測試->回報結果

而實際上 DEMO 時我所使用的程式是:

noscat 'nosetests --with-growl -w sanity/tests' sanity

1. noscat: 進行檔案的監測並執行對應的指令

2. 'nosetests --with-growl -w sanity/tests': 測試並回報結果

3. sanity: 要監視的檔案(或目錄)

關於 2. 的部份,不同的程式或框架有不同的測試回報,如果你未曾試過為程式寫測試碼,那麼也許你根本不需要這種東西,不如來去看場電影實在。但若你對敏捷開發有興趣、對軟體測試有熟悉,或對 debug 五年前未發現的問題記恨在心,那麼你應該試一下測試驅動開發 (Test-Driving Development, TDD)。

不論如何,是一個有趣又有收護又有點頭暈又累的 COSCUP 第一天。

當然,DEMO 用的 (Python, Pylons, nosetests, noscat) 都很巧地是 Open Source。 ;)

另外,我的確在徵友……關於軟體開發方面。若有任何棲息於大台南的 code developer,請知會我一聲吶。都一年了…

六月 17, 2009
» 測試貓 noscat - 但我從沒想養貓啊

最近程式塗著玩著,就生了一隻伯特與一隻貓。

bot 下次聊。丟出這隻貓先。

這隻貓名 noscat,喜歡盯著東西跑。

驅動它的方式是:

python noscat 'nosetests -w app/tests/lib' app/lib app/model ...

這會讓它有如下的反應:

它會先饋集 app/lib 及 app/model (你可以繼續增加) 下面的所有檔案,然後(在 shell 中)跑一次 'nosetests -w app/tests/lib' 這指令。

接著一旦它收集的檔案有所更動,它就會再跑一次那指令。

你可以從這裡下載這隻貓。

For test-driving, you always need a cat.

Update 2009-06-17: 修正所給的路徑並未被確實監視。加入忽略特定副檔名(如*.swp 及 *.pyc)功能。

biggo.com.tw

A Django site.