Python je momentalne muj nejoblibenejsi jazyk. Je rychly na prototypovani, umoznuje psat kratke skripty, velke GUI aplikace, webove stranky,…
Jednou z jeho nejvetsich (ne)vyhod je, ze jde o interpretovany jazyk. Tudiz je pomalejsi, nez jazyky kompilovane a kazdy muze videt zdrojovy kod.
Problem se nastesti da relativne snadno vyresit kompilaci.
Nebudu to rozebirat nijak do hloubky. Kdo chce podrobnosti, odkazu ho na pouzite zdroje v zaveru a na Google. Jde pouze o ukazani moznosti.
Prvni ukazka. Jednoduchy program na vypis aktualniho casu. Po spusteni jako samostatny program vypise cas a ukonci se. Pri importu jako modul v pythonu nevypise nic, ceka na zavolani funkce cas().
from datetime import datetime
def mojeFunkce(cas):
print "Je %s hodin." % cas
def cas():
hodiny = datetime.now().strftime('%H:%M:%S')
mojeFunkce(hodiny)
if __name__ == '__main__':
print "_RUN_"
cas()
else:
print "import"
martin@martin:~$ cython --embed prvni.py martin@martin:~$ gcc prvni.c -I/usr/include/python2.7 -lpython2.7 -o prvni martin@martin:~$ s -lh celkem 172K -rwxr-xr-x 1 martin martin 48K pro 8 13:03 prvni -rw-r--r-- 1 martin martin 112K pro 8 13:03 prvni.c -rw-r--r-- 1 martin martin 268 pro 8 13:02 prvni.py -rw-r--r-- 1 martin martin 541 pro 8 13:02 prvni.pyc martin@martin:~$ strip prvni martin@martin:~$ ls -lh celkem 164K -rwxr-xr-x 1 martin martin 37K pro 8 13:03 prvni -rw-r--r-- 1 martin martin 112K pro 8 13:03 prvni.c -rw-r--r-- 1 martin martin 268 pro 8 13:02 prvni.py -rw-r--r-- 1 martin martin 541 pro 8 13:02 prvni.pyc martin@martin:~$ ./prvni _RUN_ Je 13:03:19 hodin martin@martin:~$ python Python 2.7.6 (default, Jun 22 2015, 17:58:13) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import prvni >>> prvni.cas() Je 13:03:33 hodin. >>> martin@martin:~$ ldd ./prvni linux-vdso.so.1 => (0x00007fff957fe000) libpython2.7.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 (0x00007f5f68c47000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5f68882000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5f68663000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f5f6844a000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5f68246000) libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f5f68042000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5f67d3c000) /lib64/ld-linux-x86-64.so.2 (0x00007f5f691db000) martin@martin:~$
Prvni prikaz (cython) vegeneruje z pythoniho zdrojoveho kodu C zdrojovy kod. Je tezko clovekem citelny, protoze je generovany. Parametr embed zajisti pridani main() funkce. Cython dokaze generovat C a C++ zdrojaky a pouzivat Python2, nebo Python3.
Pote je mozne vygenerovany C soubor pomoci gcc zkompilovat. Stripnuta binarka ma jenom 37kB.
Pri spusteni jako samotny program (./prvni) vypise _RUN_. Zavislosti (viz vystup ldd) jsou bezne linuxove knihovny plus navic libpython.
Druha ukazka je o trochu slozitejsi. Pomoci skvele knihovny requests stahne JSON z meteostanice a vypise aktualni teplotu.
import requests
import json
import time
import sys
try:
debug = sys.argv[1]
except IndexError:
debug = 0
def stahniData(debug):
url = 'http://teplomer.jicin.cz/vystup-json.php'
headers = {'user-agent': 'Python_test_app/0.0.1'}
r = requests.get(url, headers=headers)
odpovedText = r.text
if debug:
print odpovedText
data = json.loads(odpovedText)
teplota = str(data['teplota'])
cas = str(data['cas'])
return teplota, cas
while True:
print 'Aktualne je {0}C, v {1}.'.format(*stahniData(debug))
time.sleep(5)
martin@martin:~$ cython --embed druhy.py
martin@martin:~$ gcc druhy.c -I/usr/include/python2.7 -lpython2.7 -O3 -o druhy
martin@martin:~$ ls -lh
celkem 340K
-rwxr-xr-x 1 martin martin 45K pro 8 13:12 druhy
-rw-r--r-- 1 martin martin 125K pro 8 13:12 druhy.c
-rw-r--r-- 1 martin martin 573 pro 8 13:11 druhy.py
martin@martin:~$ strip druhy
martin@martin:~$ ls -lh
celkem 328K
-rwxr-xr-x 1 martin martin 34K pro 8 13:13 druhy
-rw-r--r-- 1 martin martin 125K pro 8 13:12 druhy.c
-rw-r--r-- 1 martin martin 573 pro 8 13:11 druhy.py
martin@martin:~$ file druhy
druhy: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=4afeb4fa92c52bf9bb549e838525ca3416281bb9, stripped
martin@martin:~$ ldd ./druhy
linux-vdso.so.1 => (0x00007fff0e72b000)
libpython2.7.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 (0x00007f9a35878000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a354b3000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a35294000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f9a3507b000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a34e77000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f9a34c73000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a3496d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a35e0c000)
martin@martin:~$ ./druhy
Aktualne je 7.1C, v 2015-12-08 13:12:35.
Aktualne je 7.1C, v 2015-12-08 13:12:35.
...
martin@martin:~$ ./druhy 1
{
"teplota": 7.1,
"vlhkost": null,
"cas": "2015-12-08 13:12:35",
"umisteni": "<a href="http://www.mapy.cz/s/hgUU">Zizkovo nam. 18</a>"
}
Aktualne je 7.1C, v 2015-12-08 13:12:35.
{
"teplota": 7.1,
"vlhkost": null,
"cas": "2015-12-08 13:12:35",
"umisteni": "<a href="http://www.mapy.cz/s/hgUU">Zizkovo nam. 18</a>"
}
Aktualne je 7.1C, v 2015-12-08 13:12:35.
...
martin@martin:~$
Mezi hodne zajimave vyhody kompilace Pythonu patri i mozne zrychleni. Python je dynamicky silne typovany jazyk. Neustale zjistovani a kontrola typu zpusobuje znatelne zpomaleni behu programu. Zvlast u nekterych vypoctu je rozdil obrovsky (proto se na vypocty ma pouzivat NumPy). Proto umoznuje Cython nadefinovat promennym datove typy.
Hodne zajimave je toto PDF. Urcite doporucuji precist. Z neho je take nasledujici ukazka:
def exp(x, terms = 50): sum = 0. power = 1. fact = 1. for i in range(terms): sum += power/fact power *= x fact *= i+1 return sum # doba behu pro 50 000 - 1,05s def exp(double x, int terms = 50): cdef double sum cdef double power cdef double fact cdef int i sum = 0. power = 1. fact = 1. for i in range(terms): sum += power/fact power *= x fact *= i+1 return sum # doba behu pro 50 000 - 0,042s # rozdil - 25x
Aneb jak se pise na oficialnim webu Cythonu: „Cython is Python with C data types“ (Cython je Python s C datovymi typy).
Pouzite zdroje: