Poniżej znajdują się przybliżone wskazówki i oparte na doświadczeniu domysły. Powinieneś timeit
lub profilować swój konkretny przypadek użycia, aby uzyskać twarde liczby, a te liczby mogą czasami nie zgadzać się z poniższymi.
Zrozumienie listy jest zwykle odrobinę szybsze niż dokładnie równoważna for
pętla (która faktycznie buduje listę), najprawdopodobniej dlatego, że nie musi sprawdzać listy i jej append
metody w każdej iteracji. Jednak składanie list nadal wykonuje pętlę na poziomie kodu bajtowego:
>>> dis.dis(<the code object for `[x for x in range(10)]`>)
1 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 12 (to 21)
9 STORE_FAST 1 (x)
12 LOAD_FAST 1 (x)
15 LIST_APPEND 2
18 JUMP_ABSOLUTE 6
>> 21 RETURN_VALUE
Używanie funkcji rozumienia listy zamiast pętli, która nie tworzy listy, bezsensowne gromadzenie listy bezsensownych wartości, a następnie odrzucanie listy, jest często wolniejsze ze względu na obciążenie związane z tworzeniem i rozszerzaniem listy. Listy składane nie są magią, która jest z natury szybsza niż stara dobra pętla.
Co do funkcjonalnej funkcji przetwarzania listy: Chociaż te są napisane w C i prawdopodobnie lepszych od równoważne funkcje napisane w Pythonie, są one nie koniecznie najszybszym rozwiązaniem. Oczekuje się pewnego przyspieszenia, jeśli funkcja jest napisana również w C. Jednak w większości przypadków przy użyciu lambda
(lub innej funkcji Pythona) obciążenie związane z wielokrotnym konfigurowaniem ramek stosu Pythona itp. Pochłania wszelkie oszczędności. Zwykłe wykonywanie tej samej pracy w linii, bez wywołań funkcji (np. Rozumienie listy zamiast map
lub filter
) jest często nieco szybsze.
Załóżmy, że w grze, którą tworzę, muszę narysować złożone i ogromne mapy, używając pętli. To pytanie byłoby zdecydowanie istotne, ponieważ jeśli na przykład rozumienie listy jest rzeczywiście szybsze, byłoby to znacznie lepszą opcją, aby uniknąć opóźnień (pomimo wizualnej złożoności kodu).
Są szanse, że jeśli taki kod nie jest już wystarczająco szybki, gdy jest napisany w dobrym, niezoptymalizowanym Pythonie, żadna ilość mikrooptymalizacji na poziomie Pythona nie sprawi, że będzie on wystarczająco szybki i powinieneś zacząć myśleć o przejściu do C. Chociaż obszerny mikrooptymalizacje mogą często znacznie przyspieszyć kod Pythona, jest to niski (w kategoriach bezwzględnych) limit. Co więcej, nawet zanim osiągniesz ten pułap, staje się po prostu bardziej opłacalne (przyspieszenie o 15% w porównaniu z przyspieszeniem o 300% przy tym samym wysiłku), aby ugryźć pocisk i napisać trochę C.
Pytasz konkretnie o
map()
,filter()
areduce()
, ale zakładam, że chcesz wiedzieć na temat programowania funkcjonalnego w ogóle. Po przetestowaniu tego samodzielnie na problemie obliczania odległości między wszystkimi punktami w zestawie punktów, programowanie funkcjonalne (z wykorzystaniemstarmap
funkcji z wbudowanegoitertools
modułu) okazało się nieco wolniejsze niż pętle for (zajmujące 1,25 razy dłuższe w fakt). Oto przykładowy kod, którego użyłem:Czy wersja funkcjonalna jest szybsza niż wersja proceduralna?
źródło
Napisałem prosty skrypt, który testuje szybkość i oto co się dowiedziałem. Właściwie pętla for była w moim przypadku najszybsza. To naprawdę mnie zaskoczyło, sprawdź poniżej (obliczałem sumę kwadratów).
źródło
int
insquare_sum4
sprawia, że jest on nieco szybszy i tylko nieco wolniejszy niż pętla for.Zmodyfikowałem kod @ Alisa i
cProfile
pokazałem, dlaczego rozumienie listy jest szybsze:Oto wyniki:
MOIM ZDANIEM:
reduce
imap
generalnie są dość powolne. Co więcej, używanie zwróconychsum
iteratorówmap
jest powolne w porównaniu zsum
listąfor_loop
używa dołączania, co oczywiście jest do pewnego stopnia powolnesum
w przeciwieństwie domap
źródło
Dodając zwrot akcji do odpowiedzi Alphii , w rzeczywistości pętla for byłaby druga najlepsza i około 6 razy wolniejsza niż
map
Główne zmiany polegały na wyeliminowaniu powolnych
sum
połączeń, a także prawdopodobnie niepotrzebnychint()
w ostatnim przypadku. Umieszczenie pętli for i mapy w tych samych warunkach czyni to właściwie. Pamiętaj, że lambdy to koncepcje funkcjonalne i teoretycznie nie powinny mieć skutków ubocznych, ale cóż, mogą mieć efekty uboczne, takie jak dodawaniea
. Wyniki w tym przypadku z Pythonem 3.6.1, Ubuntu 14.04, Intel (R) Core (TM) i7-4770 CPU @ 3,40 GHzźródło
Udało mi się zmodyfikować część kodu @ alpiii i odkryłem, że rozumienie list jest trochę szybsze niż pętla for. Może to być spowodowane przez
int()
, nie jest sprawiedliwe między zrozumieniem listy a pętlą for.źródło