Vsebina
Zakaj ta delavnica sploh obstaja
Če se ukvarjate z raziskovalnim računanjem, ste verjetno že doživeli oba ekstrema:
- Python je odličen za hitro preverjanje idej in povezovanje različnih orodij.
- Python postane boleče počasen, ko je glavno delo tesna numerična zanka.
Večina skupin zato pristane pri razdeljeni arhitekturi:
- Python za orkestracijo (V/I, prelete parametrov, risanje grafov, skripte za posle).
- C/C++/Fortran za jedra (del, ki v resnici porabi čas na CPE/GPE).
Vprašanje ni »ali naj uporabljam Python ali C++?« Vprašanje je: kje postavim mejo in kako jo prečkam brez kaosa?
pybind11 je v sodobnih C++ projektih eden najpogosteje uporabljenih odgovorov: omogoči, da iz C++ sestavite Python modul z razmeroma malo dodatne navlake. Namen pybind11 je, da C++ stran ostane »navaden C++«, Python stran pa »navaden Python«.
Konkreten miselni model: kaj se zgodi pri import
Ko zaženete:
import hello
Python ne počne nič mističnega. Išče modul z imenom hello:
- datoteko
hello.py, ali - mapo paketa
hello/, ali - prevedeno razširitev, npr.
hello*.so(Linux),hello*.pyd(Windows) itd.
Projekt pybind11 proizvede prav to tretjo možnost: prevedeno razširitev.
Ko jo Python naloži, pokliče posebno vstopno funkcijo, definirano z makrom
PYBIND11_MODULE(name, m). To je dobesedno funkcija, ki se izvede ob import.
Kaj s kombinacijo Python + C++ pridobite
Prehod med jezikoma ima ceno, zato je naravno vprašanje: zakaj bi se tega sploh lotili?
Pri raziskovalni programski opremi so koristi običajno zelo praktične:
- Hitrost tam, kjer šteje: vročo zanko (kernel) prestavite v C++, Python pa pustite za orkestracijo.
- Ponovna uporaba obstoječih C++ knjižnic: veliko zrelih numeričnih in domenskih knjižnic je v C++ (ali prek C API).
- Čistejši raziskovalni potek dela: Python ostane »lepilo« za prelete parametrov, beležnice, grafe in V/I, C++ pa ostane osredotočen na račun.
- Pot do skaliranja: ko je jedro v C++, je kasneje precej lažje dodati OpenMP/MPI/GPU podporo, ne da bi prepisali analizo.
Ključ je v zasnovi vmesnika: overhead naj plačate redko, hitrost C++ pa izkoristite pogosto.
Prehod med jezikoma ima realen overhead:
- Python objekte je treba preveriti in pretvoriti v C++ vrednosti.
- Upravljati je treba reference in življenjski cikel objektov.
- Polja se lahko kopirajo, če razporeditev v pomnilniku ne ustreza temu, kar pričakuje C++.
Iz tega sledi prvo pravilo zmogljivosti, ki ga je vredno ponotranjiti:
C++ pokličite enkrat na paket dela, ne enkrat na skalar.
Slab vzorec (prehod se ponovi milijonkrat):
for i in range(N):
y[i] = cpp_scale(x[i], 2.0)
Boljši vzorec (en klic, zanka je v C++):
y = cpp_scale_vector(x, 2.0)
V modulih 4 in 5 bomo idejo »dela v paketih« naredili zelo konkretno.
Viri
- pybind11 “First steps / basics” (osnovno vezanje funkcij): https://pybind11.readthedocs.io/en/stable/basics.html
- referenca
PYBIND11_MODULE: https://pybind11.readthedocs.io/en/stable/reference.html