2016-03-22 22 views
1

benim kodudur:Python timeit: Her tekrardan önce zamanlanmış işlev için argümanlar nasıl başlatılır? Diyelim ki ben burada bir sıralama işlevi yürütme zamanı ölçmek için çalışıyorum diyelim

import timeit 

def time_algo(sort_fun, input_seq, num=100): 
    ''' 
    Time how long it takes to sort sequence 'input_seq' using 
    function 'sort_fun'. Take min of 'num' times. 
    ''' 
    foo = list(input_seq) 
    wrapped = wrapper(sort_fun, foo) 
    return min(timeit.repeat(wrapped, repeat=num, number=1)) 

def wrapper(func, *args): 
    def wrapped(): 
     return func(*args) 
    return wrapped 

print time_algo(list.sort, [10,9,8,7,6,5,4,3,2,1], num = 100) 

sorun sort_fun ilk idamından sonra, giriş listesi önceden sıralandığını olduğunu ve var num - 1 kez geri kalanı için sıralanmış bir listede çalışıyor.

İşlev zamanlamasının her tekrar edilmesinden önce giriş işlevi argümanlarını (bu durumda foo = list(input_seq)'u yürütün) nasıl başlatabilirim? Veya timeit modülünü kullanarak bunu yapmanın doğru yolu ne olurdu (doğru sonuçlara ihtiyacım var, bu yüzden time.clock() vb. Gibi diğer zamanlama yöntemlerini kullanmak istemiyorum)?

+0

"Zamanlama" sonucuna dahil edilen bir kopyanın zamanlamasına sahip olmanın sakıncası var mı? – MSeifert

+0

İşte tam olarak burada kaçınmaya çalışıyorum :) –

+0

Bu zor olacak. İşlevinizin, argümanlarını değiştirmemesi için test edilmesini istersiniz. Veya her arama için bir kopyasını yapmanız gerekir. Ancak, fonksiyonun çalışması için önemli bir süre geçmedikçe, siz (veya timeit uygulaması), her aramanın etrafında zamanlamayı başlatamaz ve durduramaz, çok kısadır, bu 'num> 1' noktasıdır. – Pierce

cevap

3

Bu time_algo() istediğini yapar modifiye düşünüyorum:

def time_algo(sort_fun, input_seq, num=100):               
    '''                        
    Time how long it takes to sort sequence 'input_seq' using          
    function 'sort_fun'. Take min of 'num' times.             
    '''                        
    foo = list(input_seq)                   
    wrapped = wrapper(sort_fun, foo)                 
    def reset_foo():                     
     foo[:] = list(input_seq)                  
    return min(timeit.timeit(wrapped, setup=reset_foo, number=1) for _ in range(num)) 

Bu yeniden kopyalar input_seq her sürümüyle gelen timeit önce foo listelemek için(). Daha genel olabilecek daha az süslü/daha elverişli yollar var: girişi kopyalayan, yeni bir sarmalayıcı yapan ve zamanlamayı çağıran düz bir döngü yazabilirsiniz.

... ama yukarıda yorumlandığı gibi, gerçekten birden çok yineleme, her bir timeit istersiniz ve bunun için gerçekten girişlerini değiştirmeyen bir işlevi zamanlamak istersiniz.

+0

Cevabınız için teşekkürler, güzel değil ama istediğimi yapıyor gibi görünüyor. Bir yan notta, kopyalama zamanlaması ve time parametresinde sayı parametresinin artırılmasının bana daha güvenilir sonuçlar vereceğini mi düşünüyorsunuz, yoksa gitmenin yolu bu mu? Benim için bu daha iyi, en azından teorik olarak .. –

+0

İşlevinizin gerçekçi boyutlu bir test girişinde ne kadar sürdüğüne bağlı olarak değişir. Eğer "uzun" bir süre alırsa (belki 10 milisaniye veya daha fazla), o zaman yukarıdaki muhtemelen iyidir. Eğer bu kadar uzun sürmez, fakat birçok kez (kullanım durumunuzda) çalışırsa, toplama/kopyalama girişini muhtemelen daha önemlidir, bu yüzden gerçekçi olmalı ve zamanlama fonksiyonuna dahil edilmelidir. Uzun sürmez ve uzun sürmezse, fark etmez. – Pierce