timeit Modülü¶
Kaynak Kodu: https://github.com/python/cpython/blob/3.5/Lib/timeit.py Belge Kaynağı: https://docs.python.org/3.5/library/timeit.html
Bu modül küçük kod parçalarının çalışma sürelerini ölçmeyi sağlar. Hem komut satırı arayüzüne hem de çağrılabilir bir arayüze sahiptir. Çalışma sürelerini ölçmek için birçok ortak tuzaktan kaçınır. Tim Peters’in O’Reilly tarafından yayımlanan Python Cookbook kitabının “Algoritmalar” bölümünün girişine de göz atın.
Temel Örnekler¶
Takip eden örnek, komut satırı arayüzünün üç değişik deyimi nasıl karşılaştırdığını gösteriyor:
python3 -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 29 usec per loop
python3 -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 3: 25.3 usec per loop
python3 -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 3: 20 usec per loop
Bu, Python arayüzünden şu kodlarla gerçekleştirilebilir:
import timeit
timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.30339929000001575
timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
0.2637243290000697
timeit.timeit('"-".join(map(str, range(100)))', number=10000)
0.2151021940001101
timeit sadece komut satırı arayüzü kullanıldığında yineleme sayısını otomatik olarak belirleyecektir. Örnekler bölümünde gelişmiş örnekler bulabilirsiniz.
Python Arayüzü¶
Modül, üç kolaylık fonksiyonu ve bir topluluk sınıfı tanımlar:
timeit.timeit(stmt=’pass’, setup=’pass’, timer=<default timer>, number=1000000, globals=None)
Verili ifadeyle, kurulum koduyla ve timer fonksiyonuyla bir Timer örneği oluşturun ve onun timeit() yöntemini çalıştırma sayıları ile çalıştırın. İsteğe bağlı globals bağımsız değişkeni, kodun çalıştırılacağı ad alanını belirtir.
Sürüm 3.5’de değiştirildi: İsteğe bağlı globals bağımsız değişkeni eklendi.
timeit.repeat(stmt=’pass’, setup=’pass’, timer=<default timer>, repeat=3, number=1000000, globals=None)
Verili ifadeyle, kurulum koduyla ve timer fonksiyonuyla bir Timer örneği oluşturun ve onun repeat() yöntemini tekrarlanma sayısı ve çalıştırma sayıları ile çalıştırın. İsteğe bağlı globals bağımsız değişkeni, kodun çalıştırılacağı ad alanını belirtir.
Sürüm 3.5’de değiştirildi: İsteğe bağlı globals bağımsız değişkeni eklendi.
timeit.default_timer()
Her zaman time.perf_counter() olan varsayılan zamanlayıcı
Sürüm 3.3’de değiştirildi: Şimdi varsayılan sayıcı time.perf_counter()
class timeit.Timer(stmt=’pass’, setup=’pass’, timer=<timer function>, globals=None)
Küçük kod parçalarının çalışma hızının zamanlaması için sınıf.
Yapıcı; zamanlamanın yapılması için bir ifade, kurulum için fazladan bir ifade ve zamanlama fonksiyonu alır. Her ifadenin varsayılan değeri pass olur; timer fonksiyonu platforma bağımlıdır (docstring modülüne bakınız). Ayrıca stmt ve setup, birbirlerinden ‘;’ işareti ile ayrılan çok sayıda ifadeyi içerebilir veya çok satır başı olan dizi değişkenlerini içermedikçe yeni satırları içerebilir. Deyim varsayılan olarak timeit’in ad alanında yürütülecektir; bu davranış, global alana bir isim alanı geçirerek kontrol edilebilir.
Birinci ifadenin çalışma hızını ölçmek için timeit() yöntemini kullanın. repeat(), timeit() yöntemini bir çok kez çağırmak ve sonuç listesini geri döndürmek için bir kolaylıktır. setup parametresinin çalışma zamanı, bütün çalışma zamanından hariç tutulmuştur.
stmt ve setup parametreleri argümansız çağrılabilen nesneler alabilir. Bu, çağrıları, sonradan timeit() fonksiyonuyla çalıştırılacak şekilde, timer fonksiyonunun içine gömer. Bu durumda ilave fonksiyon çağrıları nedeniyle zamanlama yükünün biraz daha fazla olacağını unutmayın.
Sürüm 3.5’de değiştirildi: İsteğe bağlı olarak globals parametresi eklendi.
timeit(number=1000000)
Ana ifadenin zaman sayısıyla ilgili çalışmaları. Bu, bir kez setup ifadesini çalıştırır ve sonra ana ifadeyi birkaç kez çalıştırmak için, float tipinde saniyelerle ölçülen zamanı geri döndürür. Döngünün kaç kez tekrar edileceğini argüman belirler, varsayılan değeri bir milyondur. Ana ifade, setup ifadesi ve timer fonksiyonu yapıcıya geçirilmek için kullanılırlar.
Not: Varsayılan olarak, timeit() fonksiyonu zamanlama süresince garbage collection’u etkisiz bırakır. Bu yaklaşımın avantajı, bağımsız zamanlamaları daha çok karşılaştırılabilir yapmaktır. Dezavantajı ise, garbage collection (çöp toplayıcısı), ölçüm esnasında fonksiyonun performansının önemli bir parçası olabilir. Böylece garbage collection (çöp toplayıcısı) setup değişkeninin (stringinin) ilk ifadesi olarak yeniden aktif edilebilir. Örneğin:
timeit.Timer("for i in range(10): oct(i)", "gc.enable()").timeit()repeat(repeat=3, number=1000000)
timeit()’i bir kaç kez çağırır.
Bu timeit()’i tekrar çağıran, sonuçları listeleyen bir kolaylık fonksiyonudur. Birinci argüman timeit()’in kaç kez çağrılacağını belirler. İkinci parametre ise timeit()’in argümanıdır.
Not: Sonuç vektörlerinden alınan değerlerin aritmetik ortalamasını ve standart sapmasını rapor olarak sunmada cazip bir yöntemdir. Ancak bu çok kullanışlı değildir. Tipik bir durumda, en küçük değer, makinenin verili kod parçasını ne kadar hızlı şekilde çalıştırdığına dair zayıf bir göstergedir; sonuç vektörleri içindeki yüksek değerler Python’ın hızının değişkenliğinden kaynaklanmaz, ancak diğer işlemlerin tutarlı zamanlama çalışmasına karışmasından kaynaklanır. Yani en düşük değer sizin ilgilenmeniz gereken tek değer olabilir. Ondan sonra, bütün vektöre bakıp istatistik yerine sağ duyuya başvurabilirsiniz.
print_exc(file=name)
Zamanlama kodunun geri izini bastırmaya yardımcı olur.
Tipik kullanım:
t = Timer(...) #try/except bloğunun dışında try: t.timeit(...) # ya da t.repeat(...) except Exception: t.print_exc()Standart geri izinin avantajı, derlenen şablondaki kaynak çizgilerinin görüntülenecek olmasıdır. İsteğe bağlı file argümanı geri izinin nereye gönderileceğini belirler, varsayılan değeri sys.stderr’dir.
Komut Satırı Arayüzü¶
Bir program olarak komut satırı arayüzünden çağrılırken şu yapı kullanılır:
python -m timeit [-n N] [-r N] [-u U] [-s S] [-t] [-c] [-h] [statement ...]
Takip eden seçenekler:
-n N, --number=N
İfadenin kaç kez çalıştırılacağını belirler.
-r N, --repeat=N
timer'ın kaç kez tekrar edileceğini (varsayılan değeri 3) belirler.
-s S, --setup=S
Bir kez ilksel olarak çalıştırılacak ifadeyi (varsayılan değeri `pass`) belirler.
-p, --process
Duvar saati zamanını değil de, işlem zamanını ölçer. Varsayılan değeri `time.perf_counter()` yerine `time.process_time()`'dir.
Sürüm 3.3'de gelmiş yeni bir özellik.
-t, --time
(onaylanmamış) `time.time()`'ı kullanır.
-u, --unit=U
Zamanlayıcı çıktısının zaman birimini belirler; usec, msec veya sec birimleri seçilebilir.
Sürüm 3.5'de gelmiş yeni bir özellik.
-c, --clock
(onaylanmamış) `time.clock()`'u kullanır.
-v --verbose
Ham zamanlama sonuçlarını bastırır, daha fazla basamak kesinliği için tekrarlar.
-h -help
Kısa bir kullanım mesajı bastırır ve sonlanır.
Çok satırlı ifadeler, her bir satırı ayrı bir ifade argümanı olacak şekilde verilebilir; girintili çizgiler, bir argümanın tırnak işaretleri içine alınarak ve önde gelen boşluklarla kullanılabilir.
Şayet -n değeri girilmezse, uygun döngü sayısı, toplam süre 0.2 saniye olana kadar onun üstleri olacak şekilde hesaplanır.
default_timer() ölçümleri makinede çalışan diğer programlar tarafından etkilenebilir, bu yüzden hassas ölçüm yapmak gerektiğinde en iyisi, zamanlamayı bir kaç kez tekrar etmek ve en uygun zamanı seçmektir. -r seçeneği bu işlem için uygundur; varsayılan üç yineleme sayısı bir çok durumda yeterlidir. CPU süresini ölçmek için time.process_time()’ı kullanabilirsiniz.
Not: Bir geçiş ifadesi çalıştırmakla ilgili belirli bir temel yük vardır. Buradaki kod bunu gizlemeye çalışmaz fakat siz bunun farkında olmalısınız. Temel yük, programı argümansız çağırarak ölçülebilir ve Python sürümleri arasında farklılıklar gösterir.
Örnekler¶
Sadece başlangıçta bir kez çalıştırılmak üzere bir setup (kurulum) ifadesi kullanılabilir:
python -m timeit -s 'text = "sample string"; char="g"' 'char in text'
10000000 loops, best of 3: 0.0482 usec per loop
python -m timeit -s 'text = "sample string"; char="g"' 'text.find(char)'
10000000 loops, best of 3: 0.178 usec per loop
Python arayüzü için:
import timeit
timeit.timeit('char in text', setup='text = "sample string"; char = "g"')
0.048954748002870474
timeit.timeit('text.find(char)', setup='text = "sample string"; char = "g"')
0.2300617519977095
Aynı işlem timer() sınıfını ve metotlarını kullanarak da yapılabilir:
import timeit
t = timeit.Timer('char in text', setup='text = "sample string"; char = "g"')
t.timeit()
0.049284196000371594
t.repeat()
[0.051710191000893246, 0.04452369999853545, 0.04527571799917496]
Sonraki örnekler çok satırlı ifadelerin zaman ölçümünün nasıl yapılacağını gösterir. Aşağıdaki örnekte, hasattr() ve try/except’in maliyeti, nesne özelliklerinin nasıl kaybedilip ortaya konduğunu test etmek için karşılaştırılmıştır:
python -m timeit 'try:' ' str.__bool__' 'except AttributeError:' ' pass'
1000000 loops, best of 3: 0.99 usec per loop
python -m timeit 'if hasattr(str, "__bool__"): pass'
1000000 loops, best of 3: 0.476 usec per loop
python -m timeit 'try:' ' int.__bool__' 'except AttributeError:' ' pass'
1000000 loops, best of 3: 0.966 usec per loop
python -m timeit 'if hasattr(int, "__bool__"): pass'
1000000 loops, best of 3: 0.479 usec per loop
Python arayüzü için:
import timeit
# özellik kayıp
s = """\
try:
str.__bool__
except AttributeError:
pass
"""
timeit.timeit(stmt=s, number=100000)
0.08558237599936547
s = "if hasattr(str, '__bool__'): pass"
timeit.timeit(stmt=s, number=100000)
0.0541383109994058
# özellik mevcut
s = """\
try:
int.__bool__
except AttributeError:
pass
"""
timeit.timeit(stmt=s, number=100000)
0.011753970000427216
s = "if hasattr(int, '__bool__'): pass"
timeit.timeit(stmt=s, number=100000)
0.016129147999890847
timeit()’i tanımladığınız fonksiyonda kullanmak için önemli bir ifade içeren bir setup parametresi geçirebilirsiniz:
def test():
"""Test fonksiyonu"""
L = [i for i in range(100)]
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))
4.163065000997449
Bir diğer seçenek şimdiki global ad alanı içerisinde çalıştırılacak globals()’i genel alan parametrelerine geçirmektir. Bu bireysel olarak içe aktarmaları belirtmeye göre daha kolaydır:
def f(x):
return x**2
def g(x):
return x**4
def h(x):
return x**8
import timeit
print(timeit.timeit('[func(42) for func in (f,g,h)]', globals=globals()))
1.632076413003233
timeit’i kullanarak benzer işlemleri yapan kodlardan hangisinin daha performanslı olduğunu görebilirsiniz:
python -m timeit '"a" + "b"'
100000000 loops, best of 3: 0.0183 usec per loop
python -m timeit '"{}.{}".format("a", "b")'
1000000 loops, best of 3: 0.215 usec per loop
python -m timeit '"%s%s" %("a", "b")'
10000000 loops, best of 3: 0.117 usec per loop
python -m timeit '"".join(("a", "b"))'
10000000 loops, best of 3: 0.109 usec per loop
Python arayüzü için:
import timeit
timeit.timeit('"a" + "b"', number=1000000)
0.018340642998737167
timeit.timeit('"{}{}".format("a", "b")', number=1000000)
0.3770097929991607
timeit.timeit('"%s%s" %("a", "b")', number=1000000)
0.2078534940010286
timeit.timeit('"".join(("a", "b"))', number=1000000)
0.1585119779992965
Önemli Not
Sorularınızı yorumlarda dile getirmek yerine Yazbel Forumunda sorarsanız çok daha hızlı cevap alabilirsiniz.Belgelerdeki bir hata veya eksiği dile getirecekseniz lütfen yorumları kullanmak yerine Github'da bir konu (issue) açın.
Eğer yazdığınız yorum içinde kod kullanacaksanız kodlarınızı <pre><code> etiketleri içine alın. Örneğin:
<pre><code class="python"> print("Merhaba Dünya!") </code></pre>