Rozumiem pojęcie tego, co timeit
robi, ale nie jestem pewien, jak zaimplementować to w moim kodzie.
Jak mogę porównać dwie funkcje, powiedzmy insertion_sort
i tim_sort
, z timeit
?
Sposób działania timeit polega na jednokrotnym uruchomieniu kodu instalacyjnego, a następnie wielokrotnym wywoływaniu szeregu instrukcji. Tak więc, jeśli chcesz przetestować sortowanie, należy zachować ostrożność, aby jedno przejście w sortowaniu lokalnym nie wpłynęło na następne przejście z już posortowanymi danymi (co oczywiście sprawiłoby, że Timsort naprawdę zabłysnął, ponieważ działa najlepiej gdy dane są już częściowo zamówione).
Oto przykład, jak skonfigurować test do sortowania:
>>> 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
Zauważ, że seria instrukcji tworzy nową kopię nieposortowanych danych przy każdym przejściu.
Zwróć także uwagę na technikę pomiaru czasu, która polega na uruchomieniu pakietu pomiarowego siedem razy i zachowaniu najlepszego czasu - może to naprawdę pomóc w zmniejszeniu zniekształceń pomiaru spowodowanych innymi procesami działającymi w systemie.
To są moje wskazówki, jak prawidłowo używać timeit. Mam nadzieję że to pomoże :-)
timsort(a)
i weź różnicę :-).repeat(7,1000)
już to robisz (używając tego samego ziarna)! Więc twoje rozwiązanie jest idealne IMO..repeat(7, 1000)
vs. ) powinien zależeć od tego, jak błąd spowodowany obciążeniem systemu porównuje się z błędem wynikającym ze zmienności danych wejściowych. W skrajnym przypadku, jeśli twój system jest zawsze obciążony i widzisz długi cienki ogon po lewej stronie rozkładu czasu wykonania (gdy złapiesz go w rzadkim stanie bezczynności), możesz nawet okazać się bardziej przydatny niż gdybyś nie może przeznaczyć więcej niż 7000 uruchomień.repeat(2, 3500)
.repeat(35, 200
.repeat(7000,1)
.repeat(7,1000)
Jeśli chcesz korzystać
timeit
z interaktywnej sesji Pythona, istnieją dwie wygodne opcje:Użyj powłoki IPython . Posiada wygodną
%timeit
funkcję specjalną:W standardowym interpretatorze Pythona można uzyskać dostęp do funkcji i innych nazw zdefiniowanych wcześniej podczas sesji interaktywnej, importując je z
__main__
instrukcji konfiguracji:źródło
from __main__ import f
techniki. Nie sądzę, że jest to tak powszechnie znane, jak powinno być. Przydaje się w takich przypadkach, w których odmierzana jest funkcja lub wywołanie metody. W innych przypadkach (odmierzanie serii kroków) jest to mniej pomocne, ponieważ wprowadza narzut wywołania funkcji.%timeit f(x)
sys._getframe(N).f_globals
) powinny być od początku domyślne.Powiem ci sekret: najlepszy sposób użycia
timeit
to w wierszu poleceń.W wierszu poleceń
timeit
wykonuje odpowiednią analizę statystyczną: pokazuje, jak długo trwał najkrótszy bieg. Jest to dobre, ponieważ każdy błąd w pomiarze czasu jest dodatni. Zatem najkrótszy czas zawiera najmniej błędów. Nie ma sposobu, aby uzyskać błąd ujemny, ponieważ komputer nigdy nie może wykonać obliczeń szybciej niż potrafi!Interfejs wiersza poleceń:
To całkiem proste, prawda?
Możesz skonfigurować różne rzeczy:
co też jest przydatne!
Jeśli chcesz mieć wiele linii, możesz albo użyć automatycznej kontynuacji powłoki, albo użyć osobnych argumentów:
To daje konfigurację
i czasy
Jeśli chcesz mieć dłuższe skrypty, możesz ulec pokusie przejścia do
timeit
wnętrza skryptu Python. Sugeruję unikanie tego, ponieważ analiza i synchronizacja są po prostu lepsze w wierszu poleceń. Zamiast tego robię skrypty powłoki:Może to potrwać nieco dłużej z powodu wielu inicjalizacji, ale zwykle nie jest to wielka sprawa.
Ale co jeśli chcesz używać
timeit
w swoim module?Cóż, prosty sposób to zrobić:
a to daje łączny ( nie minimalny!) czas na uruchomienie tej liczby razy.
Aby uzyskać dobrą analizę, użyj
.repeat
i weź minimum:Zwykle powinieneś połączyć to z
functools.partial
zamiastlambda: ...
obniżać koszty ogólne. W ten sposób możesz mieć coś takiego:Możesz także:
co dałoby ci coś bliższego interfejsu z wiersza poleceń, ale w znacznie mniej fajny sposób.
"from __main__ import ..."
Pozwala używać kodu z głównego modułu wewnątrz środowiska stworzonego przez sztucznątimeit
.Warto zauważyć, że jest to wygodne opakowanie,
Timer(...).timeit(...)
więc nie jest szczególnie dobre w czasie. Osobiście zdecydowanie wolę używać,Timer(...).repeat(...)
jak pokazano powyżej.Ostrzeżenia
timeit
Wszędzie istnieje kilka zastrzeżeń z tym związanych.Koszty ogólne nie są rozliczane. Powiedz, że chcesz mieć czas
x += 1
, aby dowiedzieć się, jak długo trwa dodawanie:Cóż, to nie jest 0,0476 µs. Wiesz tylko, że to mniej niż to. Wszystkie błędy są pozytywne.
Więc spróbuj znaleźć czysty narzut:
To dobre 30% narzutu od samego momentu! Może to znacznie wypaczyć względne czasy. Ale tak naprawdę zależało ci tylko na dodawaniu czasu; czasy przeglądania
x
również muszą być uwzględnione w kosztach ogólnych:Różnica nie jest dużo większa, ale jest.
Metody mutowania są niebezpieczne.
Ale to całkowicie źle!
x
jest pustą listą po pierwszej iteracji. Musisz ponownie zainicjować:Ale wtedy masz dużo kosztów ogólnych. Uwzględnij to osobno.
Zauważ, że odejmowanie narzutu jest tutaj uzasadnione tylko dlatego, że narzut stanowi ułamek czasu.
Na przykład warto zauważyć, że zarówno Sortowanie wstawiane, jak i Sortowanie czasowe mają zupełnie nietypowe zachowania czasowe dla już posortowanych list. Oznacza to, że będziesz potrzebować pośredniego
random.shuffle
sortowania, jeśli chcesz uniknąć rujnowania swoich czasów.źródło
timeit
z programu, ale działając tak samo jak w wierszu poleceń? .timeit
wykonujepass
polecenie, gdy nie podano żadnych argumentów, co oczywiście zajmuje trochę czasu. Jeśli podanepass
zostaną jakiekolwiek argumenty, nie zostaną wykonane, więc odjęcie niektórych0.014
usecs od każdego czasu byłoby niepoprawne.Jeśli chcesz szybko porównać dwa bloki kodu / funkcji, możesz:
źródło
Uważam, że najłatwiejszym sposobem użycia timeit jest z wiersza poleceń:
Biorąc pod uwagę test.py :
uruchom czas w następujący sposób:
źródło
dla mnie to najszybszy sposób:
źródło
źródło
Działa to świetnie:
źródło
pozwala skonfigurować ten sam słownik w każdym z poniższych i przetestować czas wykonania.
Argumentem konfiguracji jest w zasadzie konfiguracja słownika
Liczba ma uruchomić kod 1000000 razy. Nie konfiguracja, ale stmt
Po uruchomieniu możesz zobaczyć, że indeks jest znacznie szybszy niż get. Możesz go uruchomić wiele razy, aby zobaczyć.
Kod w zasadzie próbuje uzyskać wartość c w słowniku.
Oto moje wyniki, twoje będą się różnić.
według indeksu: 0.20900007452246427
przez get: 0,54841166886888
źródło
po prostu przekaż cały kod jako argument timeit:
źródło
źródło
gc.enable()
?Wbudowany moduł timeit działa najlepiej z wiersza polecenia IPython.
Do funkcji czasowych z poziomu modułu:
źródło
Przykład użycia interpretera REPL w języku Python z funkcją akceptującą parametry.
źródło
Utworzyłbyś dwie funkcje, a następnie uruchomiłeś coś podobnego do tego. Zauważ, że chcesz wybrać tę samą liczbę wykonania / uruchomienia, aby porównać jabłko z jabłkiem.
Zostało to przetestowane pod Pythonem 3.7.
Oto kod ułatwiający kopiowanie
źródło