Od razu ostrzegam, że sprawdzenia robiłem na szybko i nie wykonywałem wielu powtórzeń dla tej samej metody. Jestem pewien, że nie sprawdziłem wszystkich możliwych sposobów, a jedynie cztery w dwóch wariantach każdy. Jeśli ktoś zna inny ze sposobów, proszę o zamieszczenie go w komentarzu, a z przyjemnością sprawdzę, jak wypada w porównaniu z poniższymi.
Do wykonania pomiarów użyłem modułu timeit i jego funkcji timeit. Dzięki temu wykonywany był pomiar wielu powtórzeń, co pozwala na uwydatnienie różnic między czasami wykonań. Każda z metod została wykonana w dwóch wariantach:
z użyciem ciągów znaków
z użyciem zmiennych, do których uprzednio przypisane były te same ciągi znaków co w wariacie pierwszym
Pierwsza z metod jaką skojarzyłem, to złączenie przez operator dodawania. W IDLE łatwo sprawdzić, że to działa:
>>> "foo" + "bar" 'foobar'Można ewentualnie bardziej zaszaleć:
>>> a, b = ("foo", "bar") >>> a + b 'foobar'W obu przypadkach wynik jest taki sam. Jak jednak wygląda czas wykonania poniższego?
>>> timeit.timeit('"foo" + "bar"') 0.0317072855809933 >>> timeit.timeit('a + b', 'a, b = ("foo", "bar")') 0.17695442069203082Jak widać wykonanie bezpośrednio na ciągach znaków jest blisko 6x szybsze. W dokumentacji nie ma słowa o tym, czy parametr setup jest liczony do pomiaru. Na tyle na ile zrozumiałem kod modułu, to jest on wykonywany tylko raz przed wykonaniem pomiaru, Tym bardziej dziwi mnie wynik i tak duża jego różnica.
Druga metoda to użycie funkcji format. Jako że staram się uczyć Python 3, a testować głównie na wersji 3.4, format jest mi dość znany i bliski. W IDLE wygląda to tak:
>>> "{0}{1}".format("foo", "bar") 'foobar'Wariant drugi to:
>>> a, b = ("foo", "bar") >>> "{0}{1}".format(a, b) 'foobar'Test dla tego rozwiazania:
>>> timeit.timeit('"{0}{1}".format("foo","bar")') 0.6440918694441109 >>> timeit.timeit('"{0}{1}".format(a,b)', 'a, b = ("foo", "bar")') 0.5819630410125995Jak łatwo zauważyć w tym przypadku użycie zmiennych jest szybsze niż użycie ciągów znaków bezpośrednio. Różnica nie jest wielka, ale zauważalna.
Trzecia metoda to łączenie elementów krotek. Do tego służy metoda join. Przykładowo w IDLE:
>>> "".join(("foo", "bar")) 'foobar'Wariant drugi:
>>> a, b = ("foo", "bar") >>> "".join((a, b)) 'foobar'Test dla tej metody:
>>> timeit.timeit('"".join(("foo", "bar"))') 0.2564672791386897 >>> timeit.timeit('"".join((a, b))', 'a, b = ("foo", "bar")') 0.2673977912679675Jak widać ta metoda jest znacznie szybsza niż użycie format. Różnica pomiędzy wariantami jest zaś bardzo nieduża.
Czwarta metoda to w zasadzie drobna modyfikacja trzeciej. Po sprawdzeniu poprzedniej, zacząłem się zastanawiać czy lista będzie szybsza od krotki. Dlatego też ponownie użyta została metoda join, ale łączeniu poddana została lista:
>>> "".join(["foo", "bar"]) 'foobar'Wariant drugi:
>>> a, b = ("foo", "bar") >>> "".join([a, b]) 'foobar'Test dla tej metody:
>>> timeit.timeit('"".join(["foo", "bar"])') 0.43746682858508734 >>> timeit.timeit('"".join([a, b])', 'a, b = ("foo", "bar")') 0.3809328838217425Jak widać zastosowanie listy jest gorszym pomysłem niż zastosowanie krotki. W sumie nie jest to dziwne, bo lista jest tworzona w każdym z miliona wywołań. Domyślam się, że stworzenie rozszerzalnej listy jest znacznie bardziej kosztowne niż stałej krotki. Nie spodziewam się, aby sam dostęp do elementów miał różny koszt czasowy.
Wspomniałem już, że pracuję na Python 3.4 i z tego powodu korzystam z metody format. W Python 2 mamy do dyspozycji operator %, który robi mniej wiecej to samo, ale ciąg z formatem jest nieco inny. Nie używam praktycznie tego operatora, ale choć odradzany, jest on ciągle wspierany w Python 3. Zgodnie z wcześniejszymi przykładami w IDLE użycie go wygląda tak:
>>> "%s%s" % ("foo", "bar") 'foobar'Wariant drugi:
>>> a, b = ("foo", "bar") >>> "%s%s" % (a, b) 'foobar'Sam test dla tej metody:
>>> timeit.timeit('"%s%s" % ("foo", "bar")') 0.031486765752106294 >>> timeit.timeit('"%s%s" % (a, b)', 'a, b = ("foo", "bar")') 0.40198046513705776Uważam za dość interesujące, że dla ciągów znaków stary operator jest tak szybki jak operator dodawania. Spodziewałem się, że wynik tego testu będzie bardzo zbliżony do wyników dla metody pierwszej. Co ciekawe użycie zmiennych powoduje spowolnienie ponad 12x. Bardzo ciekaw jestem skąd może to wynikać.
Brak komentarzy:
Prześlij komentarz