Yanıtlar:
Yolu sürümüyle gelen timeit çalışır kez kurulum kod çalıştırmasına ve sonra tabloların bir dizi tekrarlanan çağrılar yapmaktır. Bu nedenle, sıralamayı test etmek istiyorsanız, yerinde sıralamada bir geçişin zaten sıralanmış verilerle bir sonraki geçişi etkilememesi için biraz dikkat gerekir (elbette, Timsort'un gerçekten en iyi performansı gösterdiği için parlamasını sağlar) veriler kısmen sipariş edildiğinde).
Sıralama için bir testin nasıl oluşturulacağına dair bir örnek:
>>> import timeit
>>> setup = '''
import random
random.seed('slartibartfast')
s = [random.random() for i in range(1000)]
timsort = list.sort
'''
>>> print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7, 1000))
0.334147930145
İfadeler dizisinin, her geçişte sıralanmamış verilerin yeni bir kopyasını oluşturduğunu unutmayın.
Ayrıca, ölçüm paketini yedi kez çalıştırma ve yalnızca en iyi zamanı tutma zamanlama tekniğine dikkat edin - bu, sisteminizde çalışan diğer işlemler nedeniyle ölçüm bozulmalarını azaltmaya gerçekten yardımcı olabilir.
Bunlar timeit'i doğru kullanmak için ipuçları. Bu yardımcı olur umarım :-)
.repeat(7,1000)
zaten bunu yapman (aynı tohumu kullanarak)! Yani çözümünüz mükemmel IMO.
.repeat(7, 1000)
Vs .repeat(2, 3500)
vs .repeat(35, 200
) nasıl ayırdığınızın, sistem yükünden kaynaklanan hatanın giriş değişkenliği nedeniyle hatayla nasıl karşılaştırıldığına bağlı olması gerektiğini ekleyebilirim. Olağanüstü bir durumda sistem ağır yük altında her zaman olur ve yürütme zamanı dağılımı (bir nadir boşta çalışma durumunda yakalamak olduğunda) ın solunda uzun ince kuyruk görürseniz, hatta bulabilir .repeat(7000,1)
daha yararlı olması için .repeat(7,1000)
eğer 7000'den fazla çalışmayı bütçeleyemez.
timeit
Etkileşimli bir Python oturumunda kullanmak istiyorsanız , iki uygun seçenek vardır:
IPython kabuğunu kullanın . Uygun %timeit
özel fonksiyona sahiptir:
In [1]: def f(x):
...: return x*x
...:
In [2]: %timeit for x in range(100): f(x)
100000 loops, best of 3: 20.3 us per loop
Standart bir Python yorumlayıcısında, etkileşimli oturum sırasında daha önce tanımladığınız işlevlere ve diğer adlara __main__
kurulum deyiminden aktararak erişebilirsiniz :
>>> def f(x):
... return x * x
...
>>> import timeit
>>> timeit.repeat("for x in range(100): f(x)", "from __main__ import f",
number=100000)
[2.0640320777893066, 2.0876040458679199, 2.0520210266113281]
from __main__ import f
Tekniği göstermek için +1 . Bunun olması gerektiği kadar yaygın olduğunu sanmıyorum. Bir işlev veya yöntem çağrısının zamanlandığı bu gibi durumlarda yararlıdır. Diğer durumlarda (bir dizi adım zamanlama), işlev çağrısı ek yükü tanıdığı için daha az yardımcı olur.
%timeit f(x)
sys._getframe(N).f_globals
) globalleri başlangıçtan itibaren varsayılan olmalıdır.
Size bir sır vereyim: Kullanmanın en iyi yolu timeit
komut satırında.
Komut satırında timeit
uygun istatistiksel analiz yapar: en kısa sürenin ne kadar sürdüğünü gösterir. Bu iyidir çünkü zamanlamadaki tüm hatalar pozitiftir. Yani en kısa zamanın içinde en az hata vardır. Negatif hata almanın bir yolu yoktur, çünkü bir bilgisayar hesaplayabildiğinden daha hızlı hesaplayamaz!
Yani, komut satırı arayüzü:
%~> python -m timeit "1 + 2"
10000000 loops, best of 3: 0.0468 usec per loop
Bu oldukça basit, ha?
Bir şeyler ayarlayabilirsiniz:
%~> python -m timeit -s "x = range(10000)" "sum(x)"
1000 loops, best of 3: 543 usec per loop
ki bu da faydalı!
Birden çok satır istiyorsanız, kabuğun otomatik devamını kullanabilir veya ayrı bağımsız değişkenler kullanabilirsiniz:
%~> python -m timeit -s "x = range(10000)" -s "y = range(100)" "sum(x)" "min(y)"
1000 loops, best of 3: 554 usec per loop
Bu bir kurulum verir
x = range(1000)
y = range(100)
ve zamanlar
sum(x)
min(y)
Daha uzun komut dosyalarına sahip olmak istiyorsanız, timeit
bir Python komut dosyasının içine taşınmak isteyebilirsiniz . Bundan kaçınmayı öneririm çünkü analiz ve zamanlama komut satırında daha iyidir. Bunun yerine, kabuk komut dosyaları oluşturma eğilimindeyim:
SETUP="
... # lots of stuff
"
echo Minmod arr1
python -m timeit -s "$SETUP" "Minmod(arr1)"
echo pure_minmod arr1
python -m timeit -s "$SETUP" "pure_minmod(arr1)"
echo better_minmod arr1
python -m timeit -s "$SETUP" "better_minmod(arr1)"
... etc
Bu, çoklu başlatmalar nedeniyle biraz daha uzun sürebilir, ancak normalde bu büyük bir sorun değildir.
Peki ya modülünüzün içinde kullanmak isterseniztimeit
?
Basit bir yol:
def function(...):
...
timeit.Timer(function).timeit(number=NUMBER)
ve bu size bu sayıyı çalıştırmak için kümülatif ( minimum değil !) zaman verir.
İyi bir analiz elde etmek için .repeat
, minimum değeri kullanın ve alın:
min(timeit.Timer(function).repeat(repeat=REPEATS, number=NUMBER))
Normalde bunu, ek yükü azaltmak functools.partial
yerine ile birleştirmelisiniz lambda: ...
. Böylece şöyle bir şey olabilir:
from functools import partial
def to_time(items):
...
test_items = [1, 2, 3] * 100
times = timeit.Timer(partial(to_time, test_items)).repeat(3, 1000)
# Divide by the number of repeats
time_taken = min(times) / 1000
Ayrıca şunları da yapabilirsiniz:
timeit.timeit("...", setup="from __main__ import ...", number=NUMBER)
bu da komut satırından arabirime daha yakın bir şey verir , ancak çok daha az serin bir şekilde. "from __main__ import ..."
Eğer yarattığı yapay çevre içindeki ana modülden kodu kullanmanızı sağlar timeit
.
Bunun kolaylık sağlayan bir paket olduğunu Timer(...).timeit(...)
ve bu nedenle zamanlamada özellikle iyi olmadığını belirtmek gerekir. Ben şahsen Timer(...).repeat(...)
yukarıda gösterdiğim gibi kullanmayı tercih ederim .
Her timeit
yerde bu tutulan birkaç uyarı var.
Genel gider muhasebeleştirilmez. x += 1
Eklemenin ne kadar sürdüğünü öğrenmek için zaman ayırmak istediğinizi varsayalım:
>>> python -m timeit -s "x = 0" "x += 1"
10000000 loops, best of 3: 0.0476 usec per loop
Peki, 0.0476 µs değil . Sadece bundan daha az olduğunu biliyorsun . Tüm hatalar olumlu.
Bu yüzden saf yükü bulmaya çalışın :
>>> python -m timeit -s "x = 0" ""
100000000 loops, best of 3: 0.014 usec per loop
Bu sadece zamanlamadan % 30 iyi bir yük! Bu göreceli zamanlamaları büyük ölçüde eğebilir. Ama sadece ekleme zamanlarını gerçekten önemsiyordunuz ; için arama zamanlamalarının x
ek yüke dahil edilmesi gerekir:
>>> python -m timeit -s "x = 0" "x"
100000000 loops, best of 3: 0.0166 usec per loop
Fark çok daha büyük değil, ama orada.
Mutasyon yöntemleri tehlikelidir.
>>> python -m timeit -s "x = [0]*100000" "while x: x.pop()"
10000000 loops, best of 3: 0.0436 usec per loop
Ama bu tamamen yanlış! x
ilk yinelemeden sonraki boş listedir. Yeniden başlatmanız gerekecek:
>>> python -m timeit "x = [0]*100000" "while x: x.pop()"
100 loops, best of 3: 9.79 msec per loop
Ama sonra çok fazla yükünüz var. Bunu ayrıca hesaplayın.
>>> python -m timeit "x = [0]*100000"
1000 loops, best of 3: 261 usec per loop
Ek yükün çıkarılmasının burada yalnızca ek yükün zamanın küçük bir kısmı olduğu için makul olduğunu unutmayın .
Örneğin, hem Ekleme Sıralaması hem de Zaman Sıralaması'nın zaten sıralı listeler için tamamen sıra dışı zamanlama davranışlarına sahip olduğunu belirtmek gerekir . Bu random.shuffle
, zamanlamalarınızı batırmaktan kaçınmak istiyorsanız, bir tür arasında ihtiyacınız olacağı anlamına gelir .
timeit
bir programdan ancak komut satırından aynı şekilde işleyen? .
timeit
bir pass
açıklama yürütür , ki bu elbette biraz zaman alır. Herhangi bir argüman belirtilmemişse, pass
olacak değil bazı çıkarılarak böylece, idam 0.014
her zamanlama gelen usecs yanlış olur.
benim için bu en hızlı yol:
import timeit
def foo():
print("here is my code to time...")
timeit.timeit(stmt=foo, number=1234567)
# Генерация целых чисел
def gen_prime(x):
multiples = []
results = []
for i in range(2, x+1):
if i not in multiples:
results.append(i)
for j in range(i*i, x+1, i):
multiples.append(j)
return results
import timeit
# Засекаем время
start_time = timeit.default_timer()
gen_prime(3000)
print(timeit.default_timer() - start_time)
# start_time = timeit.default_timer()
# gen_prime(1001)
# print(timeit.default_timer() - start_time)
Bu harika çalışıyor:
python -m timeit -c "$(cat file_name.py)"
aşağıdakilerin her birinde aynı sözlüğü ayarlayalım ve yürütme süresini test edelim.
Kurulum argümanı temel olarak sözlüğü kurmaktır
Sayı, kodu 1000000 kez çalıştırmak içindir. Kurulum değil, stmt
Bunu çalıştırdığınızda, dizinin daha hızlı olduğunu görebilirsiniz. Görmek için birden fazla kez çalıştırabilirsiniz.
Kod temel olarak sözlükte c değerini almaya çalışır.
import timeit
print('Getting value of C by index:', timeit.timeit(stmt="mydict['c']", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
print('Getting value of C by get:', timeit.timeit(stmt="mydict.get('c')", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
İşte sonuçlarım, seninki farklı olacak.
dizine göre: 0.20900007452246427
tarafından elde: 0.54841166886888
kodunuzun tamamını timeit argümanı olarak iletmeniz yeterlidir:
import timeit
print(timeit.timeit(
"""
limit = 10000
prime_list = [i for i in range(2, limit+1)]
for prime in prime_list:
for elem in range(prime*2, max(prime_list)+1, prime):
if elem in prime_list:
prime_list.remove(elem)
"""
, number=10))
import timeit
def oct(x):
return x*x
timeit.Timer("for x in range(100): oct(x)", "gc.enable()").timeit()
gc.enable()
?
Yerleşik timeit modülü en iyi IPython komut satırından çalışır.
Bir modül içindeki işlevleri zamanlamak için:
from timeit import default_timer as timer
import sys
def timefunc(func, *args, **kwargs):
"""Time a function.
args:
iterations=3
Usage example:
timeit(myfunc, 1, b=2)
"""
try:
iterations = kwargs.pop('iterations')
except KeyError:
iterations = 3
elapsed = sys.maxsize
for _ in range(iterations):
start = timer()
result = func(*args, **kwargs)
elapsed = min(timer() - start, elapsed)
print(('Best of {} {}(): {:.9f}'.format(iterations, func.__name__, elapsed)))
return result
Parametreleri kabul eden fonksiyonla Python REPL yorumlayıcısının nasıl kullanılacağına örnek.
>>> import timeit
>>> def naive_func(x):
... a = 0
... for i in range(a):
... a += i
... return a
>>> def wrapper(func, *args, **kwargs):
... def wrapper():
... return func(*args, **kwargs)
... return wrapper
>>> wrapped = wrapper(naive_func, 1_000)
>>> timeit.timeit(wrapped, number=1_000_000)
0.4458435332577161
İki işlev oluşturup buna benzer bir şey çalıştırırsınız. Dikkat edin, elmayı elma ile karşılaştırmak için aynı sayıda yürütme / çalıştırma seçin.
Bu Python 3.7 altında test edilmiştir.
!/usr/local/bin/python3
import timeit
def fibonacci(n):
"""
Returns the n-th Fibonacci number.
"""
if(n == 0):
result = 0
elif(n == 1):
result = 1
else:
result = fibonacci(n-1) + fibonacci(n-2)
return result
if __name__ == '__main__':
import timeit
t1 = timeit.Timer("fibonacci(13)", "from __main__ import fibonacci")
print("fibonacci ran:",t1.timeit(number=1000), "milliseconds")
timsort(a)
ve farkı alın :-)