Skoči na vsebino

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:

  1. datoteko hello.py, ali
  2. mapo paketa hello/, ali
  3. 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