Wydajnosc Pythona
Transkrypt
Wydajnosc Pythona
Plan 1 Uwagi na temat wydajności CPython’a 2 Podstawowe techniki poprawiające wydajność obliczeniową 3 Podstawowe techniki poprawiające zużycie pamięci krótkie opisy modułów 1 array - jak oszczędzić na pamięci 2 ctypes - prosta integracja z C 3 multiprocessing - zrównoleglanie programu Łukasz Ligowski, Sławomir Walkowiak (ICM UW) Wydajność Pythona 19 stycznia 2010 1 / 10 Ogólnie Wydajność obliczeniowa wydajność Pythona zależy od użytego intepretera CPython nie jest zbyt szybki (wolniejszy niż Java) Operacje oraz typy danych wbudowane w intepreter są zwykle szybsze. Duża część modułów Pythona jest zaimplementowana w C/C++ co przekłada się na odpowiednią wydajność Typy wbudowane również zaimplementowane są w C Zużycie pamięci - CPython Niektóre obiekty czysto Pythonowe zajmują więcej miejsca w pamięci niż można by się spodziewać CPython rezerwuje sobie listy obiektów podręcznych które czasami zajmują zbyt dużo miejsca Łukasz Ligowski, Sławomir Walkowiak (ICM UW) Wydajność Pythona 19 stycznia 2010 2 / 10 Wydajność obliczeniowa czyli dlaczego nie lubimy kropek. . . Redukcja ilości odwołań do słowników Każde odwołanie się do obiektu który nie znajduje się w aktualnej przestrzeni adresowej kosztuje dodatkowe sprawdzenie w słowniku a ponieważ funkcje też są obiektami to. . . tablica = [] for i in xrange(1000000): tablica.append(i) . . . to szybciej będzie w ten sposób tablica = [] dodaj_element = tablica.append for i in xrange(1000000): dodaj_element(i) Łukasz Ligowski, Sławomir Walkowiak (ICM UW) Wydajność Pythona 19 stycznia 2010 3 / 10 Wydajność obliczeniowa każda “kropka” więcej spowalnia program class Obiekt(object): def __init__(self): self.tablica = [] o = Obiekt() for i in xrange(1000000): o.tablica.append(i) jeśli można najlepiej jest użyć funkcji wbudowanej. . . tablica = range(1000000) . . . lub generator expression tablica = [i for i in xrange(1000000)] Łukasz Ligowski, Sławomir Walkowiak (ICM UW) Wydajność Pythona 19 stycznia 2010 4 / 10 Wydajność obliczeniowa importowanie Z tego samego powodu co w poprzednich przykładach lepiej stosować formę importu from modul import funkcja funkcja() niż import modul modul.funkcja() Łukasz Ligowski, Sławomir Walkowiak (ICM UW) Wydajność Pythona 19 stycznia 2010 5 / 10 Zużycie pamięci CPython tworzy bufory obiektów prostych (np. int) do ponownego wykorzystania >>> a = range(10000000) >>> del a oznacza to że po wykonaniu drugiego polecenia ilość pamięci zajmowanej przez Python’a nie spadnie do poziomu początkowego uwagi tablica 10 000 000 liczb (int) zajmuje około 300 MB W normalnej pracy efekt ten nie jest zauważalny i pojawia się jedynie wtedy gdy chcemy przetwarzać duże ilości danych w jednym momencie. Łukasz Ligowski, Sławomir Walkowiak (ICM UW) Wydajność Pythona 19 stycznia 2010 6 / 10 moduł array array pozwala na wydajne przechowywanie wartości tego samego typu dd id=/dev/zero of=100MB bs=1048576 count=100 array będzie zajmować w pamięci tyle ile się spodziewamy i po skasowaniu pamięć zostanie zwolniona from array import array a = array("c") with open("100MB") as f: a.fromfile(f, 100*1024*1024) raw_input() del a raw_input() Łukasz Ligowski, Sławomir Walkowiak (ICM UW) Wydajność Pythona 19 stycznia 2010 7 / 10 moduł multiprocessing reklama Zrównoleglanie programów w Pythonie jest bardzo proste. program jednordzeniowy from math import sqrt pierwiastki = sum(map(sqrt, range(10000000))) program wielordzeniowy from math import sqrt def przelicz(zakres): return sum(map(range(*zakres))) if __name__ == "__main__": from multiprocessing import Pool procesy = Pool() pierwiastki_partial = procesy.map(przelicz, [(0, 5000000), (5000000, 10000000)]) pierwiastki = sum(pierwiastki_partial) Łukasz Ligowski, Sławomir Walkowiak (ICM UW) Wydajność Pythona 19 stycznia 2010 8 / 10 moduł ctypes reklama Z Pythona można załadować i używać dowolnych współdzielonych bibliotek w C. Zarówno pod Windows jak i Linux. program w czystym Pythonie from math import sqrt pierwiastki = sum(map(sqrt, range(10000000))) funkcja w C # include <math.h> float pierwiastki(float* tablica, int rozmiar){ float wynik = 0; for (int i = 0; i < rozmiar; i++){ wynik += sqrt(tablica[i]); }; return wynik; }; Łukasz Ligowski, Sławomir Walkowiak (ICM UW) Wydajność Pythona 19 stycznia 2010 9 / 10 moduł ctypes Kompilujemy kod w C: gcc -O3 -fPIC funkcja.c --shared -o funkcja.o -std=c99 -ggdb nowy program w Pythonie from ctypes import cdll, c_float, c_void_p from array import array lib = cdll.LoadLibrary("funkcja.o") tablica = array("f", xrange(10000000)) pierwiastki_funkcja = lib.pierwiastki pierwiastki_funkcja.restype = c_float pierwiastki_funkcja.argtypes = [c_void_p, c_int] wskaznik, liczba_elementow = tablica.buffer_info() pierwiastki = pierwiastki_funkcja(wskaznik, liczba_elementow) Łukasz Ligowski, Sławomir Walkowiak (ICM UW) Wydajność Pythona 19 stycznia 2010 10 / 10