Po co kompilować kod Pythona?

241

Dlaczego miałbyś skompilować skrypt Pythona? Możesz uruchomić je bezpośrednio z pliku .py i działa dobrze, więc czy istnieje przewaga wydajności czy coś takiego?

Zauważyłem również, że niektóre pliki w mojej aplikacji są kompilowane do pliku .pyc, podczas gdy inne nie, dlaczego?

ryeguy
źródło
Możesz również zauważyć, że włączając szybsze uruchamianie aplikacji, zyskujesz także bezpieczeństwo, jeśli nie możesz udostępnić swojego kodu, jeśli jest to tajemnica korporacyjna.
Please_Dont_Bully_Me_SO_Lords
@PSyLoCKe Naprawdę, naprawdę nie. Kod bajtowy Pythona jest naprawdę czytelny, ponieważ kompilator nie musi go zaciemniać, aby go zoptymalizować. (Nie żeby to dużo optymalizowało ...)
wizzwizz4
1
Niektóre pliki są kompilowane automatycznie, ponieważ są importowane; na przykład, jeśli używasz import mylib.py, Python skompiluje się mylib.py, aby przyszłe importinstrukcje działały nieco szybciej. Jeśli później zmienisz mylib.py, to przy następnym importowaniu zostanie ponownie skompilowana (Python używa daty pliku, aby zobaczyć, że tak się dzieje.)
fyngyrz

Odpowiedzi:

270

Jest skompilowany do kodu bajtowego, którego można używać znacznie, znacznie, znacznie szybciej.

Powodem, dla którego niektóre pliki nie są kompilowane, jest to, że skrypt główny, który wywołujesz, python main.pyjest rekompilowany przy każdym uruchomieniu skryptu. Wszystkie importowane skrypty zostaną skompilowane i zapisane na dysku.

Ważny dodatek Ben Blank :

Warto zauważyć, że podczas pracy skompilowany skrypt ma szybszego uruchamiania czas (jak to nie musi być kompilowany), to nie działać szybciej.

Georg Schölly
źródło
260
Warto zauważyć, że podczas pracy skompilowany skrypt ma szybszego uruchamiania czas (jak to nie musi być kompilowany), to nie działać szybciej.
Ben Blank
24
Powszechne nieporozumienie. Dzięki za udostępnienie.
matpie
1
Poza tym, że nie wymaga kompilacji, plik .pyc jest prawie zawsze mniejszy. Zwłaszcza jeśli dużo komentujesz. Jeden z moich to 28419 jako .py, ale tylko 17879 jako .pyc - więc czas ładowania jest również lepszy. Na koniec możesz wstępnie skompilować skrypty najwyższego poziomu w ten sposób: python -m compileall myscript.py
fyngyrz
1
Czy jest jakaś różnica w zużyciu pamięci? Testuję Python na urządzeniach osadzonych opartych na procesorze mips z jedynie 64 MB pamięci RAM, więc czy jest jakaś korzyść z wykorzystania pamięci podczas uruchamiania skompilowanej wersji skryptu python?
valentt
1
@valentt: Prawdopodobnie nie. Nie wiem dużo o wewnętrznych elementach Pythona, ale nie sądzę, że parsowanie do kodu bajtowego zajmuje w Pythonie dużo pamięci. Nie mogę wymyślić czegoś, co wymaga dużo pamięci, aby zapamiętać jakiś stan.
Georg Schölly,
80

Plik .pyc to Python, który został już skompilowany do kodu bajtowego. Python automatycznie uruchamia plik .pyc, jeśli znajdzie plik o takiej samej nazwie jak wywoływany plik .py.

„Wprowadzenie do Pythona” mówi o skompilowanych plikach Python:

Program nie działa szybciej, gdy jest czytany z pliku „.pyc” lub „.pyo”, niż gdy jest czytany z pliku „.py”; jedyną rzeczą, która jest szybsza w plikach „.pyc” lub „.pyo”, jest szybkość ich ładowania.

Zaletą uruchamiania pliku .pyc jest to, że Python nie musi ponosić kosztów kompilacji przed uruchomieniem. Ponieważ Python skompilowałby się do kodu bajtowego przed uruchomieniem pliku .py, nie powinno być żadnej poprawy wydajności.

Ile ulepszeń można uzyskać, korzystając ze skompilowanych plików .pyc? To zależy od tego, co robi skrypt. W przypadku bardzo krótkiego skryptu, który po prostu wypisuje „Hello World”, kompilacja może stanowić duży procent całkowitego czasu uruchamiania i uruchamiania. Ale koszt skompilowania skryptu w stosunku do całkowitego czasu pracy zmniejsza się w przypadku dłuższych skryptów.

Skrypt, który nazwiesz w wierszu polecenia, nigdy nie jest zapisywany w pliku .pyc. Tylko moduły ładowane przez ten „główny” skrypt są zapisywane w ten sposób.

Bill Karwin
źródło
3
W wielu przypadkach trudno dostrzec różnicę, ale mam konkretny plik Pythona z ponad 300 000 linii. (Jest to zestaw obliczeń matematycznych wygenerowanych przez inny skrypt do testowania) Kompilacja zajmuje 37 sekund, a wykonanie tylko 2 sekundy.
wojtów
54

Plusy:

Po pierwsze: łagodne, możliwe do pokonania zaciemnienie.

Po drugie: jeśli kompilacja spowoduje znacznie mniejszy plik, otrzymasz krótszy czas ładowania. Ładne dla sieci.

Po trzecie: Python może pominąć krok kompilacji. Szybszy przy początkowym obciążeniu. Ładne dla procesora i sieci.

Po czwarte: im więcej komentujesz, tym mniejszy jest plik .pyclub .pyow porównaniu do źródła.py pliku .

Po piąte: użytkownik końcowy posiadający tylko a .pyclub.pyo plik w ręku, znacznie rzadziej przedstawia ci błąd, który spowodował przez nieodwróconą zmianę, o której zapomniał ci powiedzieć.

Po szóste: jeśli dążysz do systemu osadzonego, uzyskanie mniejszego rozmiaru pliku do osadzenia może stanowić znaczący plus, a architektura jest stabilna, więc wada, opisana poniżej, nie wchodzi w grę.

Kompilacja na najwyższym poziomie

Warto wiedzieć, że można skompilować plik źródłowy Pythona najwyższego poziomu do .pycpliku w ten sposób:

python -m py_compile myscript.py

To usuwa komentarze. Pozostawia docstringsnietknięty. Jeśli chcesz się tego pozbyć docstrings(możesz poważnie zastanowić się, dlaczego to robisz), a następnie skompiluj w ten sposób ...

python -OO -m py_compile myscript.py

... a otrzymasz .pyoplik zamiast .pycpliku; równomiernie dystrybuowany pod względem podstawowej funkcjonalności kodu, ale mniejszy ze względu na rozmiar okrojony docstrings(i mniej zrozumiały dla późniejszego zatrudnienia, gdyby był przyzwoitydocstrings ). Ale patrz wada trzecia poniżej.

Zauważ, że Python używa daty .pypliku, jeśli jest obecny, aby zdecydować, czy powinien on wykonać .pyplik, a nie plik .pyclub .pyo--- - więc edytuj plik .py, a .pyclub .pyojest przestarzały, a wszelkie korzyści, które uzyskałeś, zostaną utracone. Musisz go ponownie skompilować, aby ponownie odzyskać korzyści .pyclub .pyokorzyści, takie jak mogą być.

Wady:

Po pierwsze: istnieje „magiczne ciasteczko” .pyci .pyopliki, które wskazują architekturę systemu, w której skompilowano plik python. Jeśli rozpowszechnisz jeden z tych plików w środowisku innego typu, ulegnie on awarii. Jeśli dystrybuujesz plik skojarzony .pyclub .pyobez niego w .pycelu ponownej kompilacji touch, zastępuje on .pyclub .pyo, użytkownik końcowy również nie może go naprawić.

Po drugie: jeśli docstringszostaną pominięte przy użyciu -OOopcji wiersza polecenia, jak opisano powyżej, nikt nie będzie w stanie uzyskać tych informacji, co może utrudnić (lub uniemożliwić) użycie kodu.

Po trzecie: -OOopcja Pythona implementuje również pewne optymalizacje zgodnie z -Oopcją wiersza poleceń; może to spowodować zmiany w działaniu. Znane optymalizacje to:

  • sys.flags.optimize = 1
  • assert instrukcje są pomijane
  • __debug__ = Fałsz

Po czwarte: jeśli celowo sprawiłeś, że twój skrypt Pythona jest wykonywalny z czymś w kolejności #!/usr/bin/pythonw pierwszym wierszu, zostanie on rozebrany .pyci .pyopliki, a funkcjonalność zostanie utracona.

Po piąte: nieco oczywiste, ale jeśli skompilujesz swój kod, nie tylko wpłynie to na jego użycie, ale również zmniejszy, często poważnie, możliwość uczenia się z pracy przez innych.

Fyngyrz
źródło
10

Zwiększono wydajność uruchamiania skompilowanego Pythona. Jednak gdy uruchomisz plik .py jako zaimportowany moduł, python skompiluje go i zapisze, i dopóki plik .py się nie zmieni, zawsze będzie korzystał ze skompilowanej wersji.

W przypadku dowolnego interpetowanego języka, gdy plik jest używany, proces wygląda mniej więcej tak:
1. Plik jest przetwarzany przez interpeter.
2. Plik jest kompilowany
3. Skompilowany kod jest wykonywany.

oczywiście używając wstępnie skompilowanego kodu możesz wyeliminować krok 2, dotyczy to Pythona, PHP i innych.

Oto interesujący post na blogu wyjaśniający różnice http://julipedia.blogspot.com/2004/07/compiled-vs-interpreted-languages.html
A oto wpis, który wyjaśnia proces kompilacji Pythona http://effbot.org/zone /python-compile.htm

UnkwnTech
źródło
9

Jak już wspomniano, można uzyskać wzrost wydajności dzięki kompilacji kodu Pythona w kodzie bajtowym. Zwykle jest to obsługiwane przez sam python, tylko dla importowanych skryptów.

Innym powodem, dla którego warto skompilować kod Pythona, może być ochrona własności intelektualnej przed kopiowaniem i / lub modyfikacją.

Możesz przeczytać więcej na ten temat w dokumentacji Pythona .

Simon B. Jensen
źródło
2
Jeśli chodzi o ochronę twojego kodu - kompilacja niewiele pomoże. Kompilacja zaciemnia - ale ktoś z tym pragnieniem dostanie twój kod niezależnie.
Josh Smeaton
1
@ josh jest to zawsze możliwe, jeśli można uzyskać dostęp do pamięci lub obejrzeć instrukcje do procesora, z wystarczającą ilością czasu i woli, aby ponownie zbudować aplikację.
UnkwnTech
5
Uzgodniono jednak, jak powiedział Unkwntech, że zawsze będzie to możliwe, jeśli osoba będzie wystarczająco zdeterminowana. Ale jestem przekonany, że to wystarczy w większości sytuacji, w których zazwyczaj chcesz po prostu ograniczyć ludziom możliwość „poprawiania” kodu ...
Simon B. Jensen
Języki, w których są kompilowane do kodu bajtowego nie są generalnie wszystko to trudne do odwrócenia kompilacji chyba podjąć dodatkowe kroki, aby je zaciemniać - jedynie kompilacji generalnie nie będzie wystarczająca.
EJoshuaS - Przywróć Monikę
7

Z pewnością istnieje różnica w wydajności podczas uruchamiania skompilowanego skryptu. Jeśli uruchamiasz normalne .pyskrypty, maszyna kompiluje je za każdym razem, gdy jest uruchamiane, a to zajmuje dużo czasu. Na nowoczesnych maszynach jest to prawie niezauważalne, ale wraz ze wzrostem skryptu może to stać się większym problemem.

matpie
źródło
7

Coś, czego nie poruszono, to kompilacja między źródłami . Na przykład,nuitka tłumaczy kod Pythona na C / C ++ i kompiluje go do kodu binarnego, który działa bezpośrednio na procesorze, zamiast kodu bajtowego Pythona, który działa na wolniejszej maszynie wirtualnej.

Może to prowadzić do znacznego przyspieszenia lub pozwoli ci pracować z Pythonem, podczas gdy twoje środowisko zależy od kodu C / C ++.

użytkownik258532
źródło
4

Używamy skompilowanego kodu do rozpowszechniania wśród użytkowników, którzy nie mają dostępu do kodu źródłowego. Zasadniczo, aby powstrzymać niedoświadczonych programistów przypadkową zmianą lub naprawą błędów bez informowania nas.

DrBwts
źródło
2

Tak, wydajność jest głównym powodem i, o ile wiem, jedynym powodem.

Jeśli niektóre pliki nie są kompilowane, być może Python nie może zapisać do pliku .pyc, być może z powodu uprawnień do katalogu lub czegoś takiego. A może nieskompilowane pliki po prostu nigdy się nie ładują ... (skrypty / moduły kompilują się dopiero przy pierwszym załadowaniu)

David Z
źródło
1

Początkujący zakładają, że Python jest kompilowany z powodu plików .pyc. Plik .pyc jest skompilowanym kodem bajtowym, który jest następnie interpretowany. Jeśli więc wcześniej uruchomiłeś kod Python i masz pod ręką plik .pyc, uruchomi się on szybciej za drugim razem, ponieważ nie musi ponownie kompilować kodu bajtowego

kompilator: kompilator to fragment kodu, który tłumaczy język wysokiego poziomu na język maszynowy

Tłumacze: Tłumacze konwertują również język wysokiego poziomu na binarne odpowiedniki do odczytu maszynowego. Za każdym razem, gdy interpreter otrzymuje kod języka wysokiego poziomu, który ma zostać wykonany, konwertuje kod na kod pośredni przed konwersją na kod maszynowy. Każda część kodu jest interpretowana, a następnie wykonywana osobno w sekwencji, a błąd znajduje się w części kodu, zatrzyma on interpretację kodu bez tłumaczenia następnego zestawu kodów.

Źródła: http://www.toptal.com/python/why-are-there-so-many-pythons http://www.engineersgarage.com/contribution/difference-between-compiler-and-interpreter

Początkujący
źródło
9
Twoja definicja „kompilatora” jest niepoprawna. Kompilator nigdy nie był w kompilacji do kodu maszynowego. Kompilator jest jedynie tłumaczem z jednego języka na inny. Dlatego mówimy, że Python „kompiluje” do kodu bajtowego, Coffeescript „kompiluje” do Javascript i tak dalej.
Ricky Stewart