Programavimas

„Cython“ pamoka: kaip pagreitinti „Python“

„Python“ yra galinga programavimo kalba, kurią lengva išmokti ir su kuria lengva dirbti, tačiau ji ne visada yra greičiausiai valdoma, ypač kai turite reikalų su matematika ar statistika. Trečiųjų šalių bibliotekos, pvz., „NumPy“, apvyniojančios C bibliotekas, gali žymiai pagerinti kai kurių operacijų našumą, tačiau kartais jums tiesiog reikia neapdoroto C greičio ir galios tiesiogiai „Python“.

„Cython“ buvo sukurtas siekiant palengvinti „Python“ C plėtinių rašymą ir leisti esamą „Python“ kodą paversti C. Be to, „Cython“ leidžia optimizuotą kodą pristatyti kartu su „Python“ programa be išorinių priklausomybių.

Šioje pamokoje apžvelgsime veiksmus, kurių reikia norint esamą „Python“ kodą paversti „Cython“ ir naudoti jį gamybinėje programoje.

Susijęs vaizdo įrašas: „Cython“ naudojimas norint pagreitinti „Python“

„Cython“ pavyzdys

Pradėkime nuo paprasto pavyzdžio, paimto iš „Cython“ dokumentų, ne itin efektyvaus integralios funkcijos įgyvendinimo:

def f (x):

grįžti x ** 2-x

def integrate_f (a, b, N):

s = 0

dx = (b-a) / N

i diapazone (N):

s + = f (a + i * dx)

grįžti s * dx

Kodas lengvai skaitomas ir suprantamas, tačiau jis veikia lėtai. Taip yra todėl, kad „Python“ turi nuolat keistis pirmyn ir atgal tarp savo objekto tipų ir mašinos neapdorotų skaitinių tipų.

Dabar apsvarstykite to paties kodo „Cython“ versiją, pabrėždami „Cython“ papildymus:

 cdef f (dvigubas x):

grįžti x ** 2-x

def integrate_f (dvigubas a, dvigubas b, int N):

cdef int

cdef dvigubas s, x, dx

s = 0

dx = (b-a) / N

i diapazone (N):

s + = f (a + i * dx)

grįžti s * dx

Šie priedai leidžia mums aiškiai deklaruoti kintamųjų tipus visame kode, kad „Cython“ kompiliatorius tuos „papuoštus“ priedus galėtų išversti į C.

Susijęs vaizdo įrašas: Kaip „Python“ palengvina programavimą

Puikiai IT, „Python“ supaprastina daugybę rūšių darbų, pradedant sistemos automatizavimu ir baigiant darbais pažangiose srityse, tokiose kaip mašininis mokymasis.

„Cython“ sintaksė

Raktažodžiai, naudojami papuošti „Cython“ kodą, nerandami įprastoje „Python“ sintaksėje. Jie buvo sukurti specialiai „Cython“, todėl bet koks jais dekoruotas kodas nebus vykdomas kaip įprasta „Python“ programa.

Tai yra labiausiai paplitę „Cython“ sintaksės elementai:

Kintamieji tipai

Kai kurie iš „Cython“ naudojamų kintamųjų tipų yra paties „Python“ tipo aidai, pvztarpt, plūdėir ilgas. Kiti „Cython“ kintamųjų tipai taip pat randami C, pvz., char arba struktūros, kaip ir tokios deklaracijos nepasirašytas ilgai. Ir kiti yra būdingi tik „Cython“ bint, C lygio Python pavaizdavimas Tiesa / melas vertybes.

cdef ir cpdef funkcijų tipai

cdef raktinis žodis nurodo „Cython“ arba „C“ tipo naudojimą. Jis taip pat naudojamas funkcijoms apibrėžti, kaip ir „Python“.

„Cython“ parašytos funkcijos naudojant „Python“ def raktinis žodis yra matomas kitiems „Python“ kodams, tačiau už jų vykdymą baudžiama. Funkcijos, kurios naudoja cdef raktinis žodis matomas tik kitam „Cython“ arba „C“ kodui, tačiau jis vykdomas daug greičiau. Jei turite funkcijų, kurios iš vidaus iškviečiamos tik iš „Cython“ modulio, naudokite cdef.

Trečias raktinis žodis, cpdef, suteikia suderinamumą tiek su „Python“ kodu, tiek su „C“ kodu tokiu būdu, kad C kodas pasiektų deklaruotą funkciją visu greičiu. Tačiau šis patogumas kainuoja:cpdef funkcijos sugeneruoja daugiau kodo ir turi šiek tiek daugiau skambučių pridėtinių išlaidų nei cdef.

Kiti „Cython“ raktiniai žodžiai

Kiti „Cython“ raktiniai žodžiai suteikia galimybę valdyti programos eigos ir elgsenos aspektus, kurių nėra „Python“:

  • gil ir nogil. Tai yra konteksto valdytojai, naudojami norint apibrėžti kodo sekcijas, kurioms reikia (su gil:) arba nereikia (su nogil:) „Python's Global Interpreter Lock“ arba GIL. C kodas, kuris neskambina į „Python“ API, gali veikti greičiau a nogil blokuoti, ypač jei jis atlieka ilgai trunkančią operaciją, pavyzdžiui, skaito iš tinklo ryšio.
  • cimportasTai nukreipia „Cython“ importuoti C duomenų tipus, funkcijas, kintamuosius ir plėtinių tipus. Pavyzdžiui, naudojamos „Cython“ programos, naudojančios savus „NumPy“ C modulius cimportas gauti prieigą prie tų funkcijų.
  • įtraukti. Tai įdeda vieno „Cython“ failo šaltinio kodą į kitą, panašiai kaip ir „C.“. Atkreipkite dėmesį, kad „Cython“ turi sudėtingesnį būdą dalytis deklaracijomis tarp kitų „Cython“ failų, ne tik įtrauktis.
  • ctypedef. Naudojamas nuorodoms į tipų apibrėžimus išoriniuose C antraštės failuose.
  • išorinis. Naudojamas su cdef nurodyti C funkcijas arba kintamuosius, esančius kituose moduliuose.
  • visuomenės / api. Naudojamas deklaracijoms daryti „Cython“ moduliuose, kurie bus matomi kitam C kodui.
  • tiesiai. Naudojamas nurodyti, kad tam tikra funkcija turėtų būti įterpta arba jos kodas turėtų būti dedamas į iškvietimo funkciją, kai tik ji naudojama, siekiant greičio. Pavyzdžiui, f funkciją pirmiau pateiktame kodo pavyzdyje galima papuošti tiesiai kad sumažėtų jo funkcijos iškvietimas, nes jis naudojamas tik vienoje vietoje. (Atkreipkite dėmesį, kad C kompiliatorius gali automatiškai atlikti savo įterpimą, bet tiesiai leidžia aiškiai nurodyti, ar kažkas turėtų būti įbrėžta.)

Nebūtina iš anksto žinoti visų „Cython“ raktinių žodžių. „Cython“ kodas paprastai rašomas palaipsniui - pirmiausia parašote galiojantį „Python“ kodą, tada pridedate „Cython“ apdailą, kad jį pagreitintumėte. Taigi galite paimti „Cython“ išplėstinę raktinių žodžių sintaksę po truputį, kiek jums to reikia.

Sudarykite „Cython“

Dabar, kai jau turime tam tikrą idėją, kaip atrodo paprasta „Cython“ programa ir kodėl ji atrodo taip, eikime per žingsnius, reikalingus „Cython“ sukompiliuoti į veikiantį dvejetainį failą.

Norėdami sukurti veikiančią „Cython“ programą, mums reikės trijų dalykų:

  1. „Python“ vertėjas. Jei galite, naudokite naujausią leidimo versiją.
  2. „Cython“ paketas. Galite pridėti „Cython“ prie „Python“ naudodami pip paketo tvarkyklė: pip įdiegti cython
  3. C kompiliatorius.

3 punktas gali būti keblus, jei kaip kūrimo platformą naudojate „Microsoft Windows“. Skirtingai nuo „Linux“, „Windows“ komplekte nėra C kompiliatoriaus kaip standartinio komponento. Norėdami tai išspręsti, paimkite „Microsoft Visual Studio Community Edition“ kopiją, kurioje yra „Microsoft“ kompiliatorius ir kuri nieko nekainuoja.

Atkreipkite dėmesį, kad nuo šio rašymo naujausia „Cython“ versija yra 0.29.16, tačiau galima naudoti „Cython 3.0“ beta versiją. Jei naudosite pip įdiegti cython, bus įdiegta naujausia ne beta versija. Jei norite išbandyti beta versiją, naudokite „pip install cython“> = 3.0a1 įdiegti naujausią „Cython 3.0“ šakos leidimą. „Cython“ kūrėjai rekomenduoja išbandyti „Cython 3.0“ filialą, kai tik įmanoma, nes kai kuriais atvejais jis sugeneruoja žymiai greitesnį kodą.

„Cython“ programos naudoja .pyx failo plėtinys. Naujame kataloge sukurkite failą pavadinimu skaičius.pyx kuriame yra aukščiau pateiktas „Cython“ kodo pavyzdys (antrasis kodo pavyzdys skiltyje „„ Cython “pavyzdys“) ir failas, pavadintas main.py kuriame yra šis kodas:

iš num import integrate_f

spausdinti (integrate_f (1.0, 10.0, 2000))

Tai yra įprasta „Python“ programa, kuri iškvies integruoti_f funkcija rastaskaičius.pyx. „Python“ kodas „mato“ „Cython“ kodą kaip dar vieną modulį, todėl jums nereikia nieko ypatingo daryti, kaip tik importuoti kompiliuotą modulį ir vykdyti jo funkcijas.

Galiausiai pridėkite failą pavadinimu setup.py su šiuo kodu:

iš distutils.core importo sąrankos iš distutils.extension importo plėtinys iš Cython. Sukurkite importavimo cythonize ext_modules = [plėtinys (r'num ', [r'num.pyx']),] setup (name = "num", ext_modules = cythonize (ext_modules),

)

setup.py paprastai naudoja „Python“ moduliui, su kuriuo jis yra susietas, įdiegti. Be to, jis gali būti naudojamas nukreipti „Python“ į šio modulio C plėtinių sudarymą. Čia mes naudojame setup.py kad sukurtumėte „Cython“ kodą.

Jei naudojate „Linux“ ir turite įdiegtą C kompiliatorių (paprastai tokiu atveju), galite kompiliuoti .pyx failą į C, vykdydami komandą:

python setup.py build_ext --inplace

Jei naudojate „Microsoft Windows“ ir „Microsoft Visual Studio 2017“ ar naujesnes versijas, turėsite įsitikinti, kad turite naujausią jų versiją sąrankos įrankiai įdiegta „Python“ (46.1.3 versija nuo šio rašymo), kol ta komanda neveiks. Tai užtikrina, kad „Python“ kūrimo įrankiai galės automatiškai aptikti ir naudoti jūsų įdiegtą „Visual Studio“ versiją.

Jei kompiliacija pavyko, kataloge turėtumėte pamatyti naujus failus: skaičius („Cython“ sugeneruotas C failas) ir failas su arba a .o plėtinys („Linux“) arba a .pyd plėtinys („Windows“). Tai yra dvejetainis failas, į kurį buvo sukompiliuotas C failas. Taip pat galite pamatyti a \ statyti pakatalogis, kuriame yra kūrimo proceso artefaktai.

Bėk python main.py, ir kaip atsakymą turėtumėte pamatyti kažką panašaus į šį:

283.297530375

Tai yra sukompiliuotos integralinės funkcijos išvestis, kuria remiasi mūsų grynas „Python“ kodas. Pabandykite žaisti su parametrais, perduotais funkcijai main.py norėdami pamatyti, kaip keičiasi išvestis.

Atminkite, kad kaskart keisdami .pyx failą, turėsite jį sukompiliuoti. (Visi jūsų įprasto „Python“ kodo pakeitimai įsigalios iškart.)

Gautame kompiliuotame faile nėra jokių priklausomybių, išskyrus „Python“ versiją, kuriai jis buvo sukompiliuotas, todėl jį galima sujungti į dvejetainį ratą. Atminkite, kad jei kode nurodote kitas bibliotekas, pvz., „NumPy“ (žr. Toliau), jas turėsite pateikti kaip programos reikalavimų dalį.

Kaip naudotis „Cython“

Dabar, kai žinote, kaip koduoti „Cythonize“, kitas žingsnis yra nustatyti, kaip jūsų „Python“ programa gali naudotis „Cython“. Kur tiksliai turėtumėte jį pritaikyti?

Norėdami pasiekti geriausių rezultatų, naudokite „Cython“, kad optimizuotumėte šias „Python“ funkcijas:

  1. Funkcijos, veikiančios glaudžiai, arba reikalaujančios ilgo apdorojimo laiko vienoje kodo „karštoje vietoje“.
  2. Funkcijos, atliekančios skaitines manipuliacijas.
  3. Funkcijos, veikiančios su objektais, kurie gali būti pavaizduoti grynu C, pvz., Pagrindiniai skaitiniai tipai, masyvai ar struktūros, o ne „Python“ objektų tipai, pvz., Sąrašai, žodynai ar rinkiniai.

„Python“ tradiciškai buvo mažiau efektyvus kilpoms ir skaitinėms manipuliacijoms nei kitos, neinterpretuojamos kalbos. Kuo labiau papuošite kodą, kad nurodytumėte, jog jame turėtų būti naudojami pagrindiniai skaitiniai tipai, kuriuos galima paversti C, tuo greičiau jis sukurs skaičių.

„Python“ objektų tipų naudojimas „Cython“ nėra problema. „Cython“ funkcijos, naudojančios „Python“ objektus, vis tiek bus kompiliuojamos, o „Python“ objektai gali būti pageidautini, kai našumas nėra svarbiausias dalykas. Bet bet kurį kodą, kuriame naudojami „Python“ objektai, apribos „Python“ vykdymo laikas, nes „Cython“ sugeneruos kodą, kad tiesiogiai adresuotų „Python“ API ir ABI.

Kitas vertas „Cython“ optimizavimo tikslas yra „Python“ kodas, kuris sąveikauja tiesiogiai su C biblioteka. Galite tiesiogiai praleisti „Python“ pakuotės kodą ir sąsają su bibliotekomis.

Tačiau „Cython“ tai darone automatiškai sugeneruoti tinkamas skambučių sąsajas toms bibliotekoms. Turėsite turėti „Cython“ nuorodą į funkcijos parašus bibliotekos antraštės failuose, naudodami a cdef extern iš deklaracija. Atminkite, kad jei neturite antraštės failų, „Cython“ yra pakankamai atlaidus, kad leistų deklaruoti išorinių funkcijų parašus, kurie apytiksliai nurodo pirmines antraštes. Bet jei įmanoma, naudokite originalus.

Viena išorinė C biblioteka, kurią „Cython“ gali naudoti iškart iš dėžutės, yra „NumPy“. Norėdami pasinaudoti greita „Cython“ prieiga prie „NumPy“ masyvų, naudokite cimport numpy (pasirinktinai su kaip np kad jo vardų sritis būtų atskirta), tada naudokite cdef teiginiai, skirti deklaruoti „NumPy“ kintamuosius, pvz cdef np.rašymas arba np.darray.

„Cython“ profiliavimas

Pirmasis žingsnis gerinant programos našumą yra jos profiliavimas - sukuriama išsami ataskaita apie tai, kur laikas praleidžiamas vykdant. „Python“ pateikia įmontuotus mechanizmus kodų profiliams generuoti. „Cython“ ne tik sujungia tuos mechanizmus, bet ir turi savo profiliavimo įrankius.

„Python“ paties profilio kūrėjas, cProfilis, generuoja ataskaitas, kurios parodo, kurios funkcijos tam tikroje „Python“ programoje užima daugiausiai laiko. Pagal numatytuosius nustatymus tose ataskaitose „Cython“ kodas nerodomas, tačiau galite įgalinti „Cython“ kodo profiliavimą įterpdami kompiliatoriaus direktyvą į viršų. .pyx failas su funkcijomis, kurias norite įtraukti į profiliavimą:

# cython: profile = True

Taip pat galite įgalinti linijinį sekimą „Cython“ sugeneruotame C kode, tačiau tai prideda daug pridėtinių išlaidų, todėl yra išjungta pagal numatytuosius nustatymus.

Atminkite, kad profiliavimas sukelia našumą, todėl būtinai išjunkite profilio kodą, kuris siunčiamas į gamybą.

„Cython“ taip pat gali generuoti kodų ataskaitas, kuriose nurodoma, kiek duota .pyx failas yra konvertuojamas į C, ir kiek jo lieka „Python“ kodas. Norėdami pamatyti, kaip tai veikia, redaguokite setup.py failą mūsų pavyzdyje ir viršuje pridėkite šias dvi eilutes:

importuoti „Cython.Compiler.Options“

Cython.Compiler.Options.annotate = Tiesa

(Arba, jei norite įgalinti komentarus, galite naudoti „setup.py“ direktyvą, tačiau aukščiau nurodytą metodą dažnai lengviau naudoti.)

Ištrinkite .c failus, sugeneruotus projekte, ir paleiskite iš naujo setup.py scenarijus viską perkompiliuoti. Kai baigsite, tame pačiame kataloge turėtumėte pamatyti HTML failą, kuris bendrina jūsų .pyx failo pavadinimą - šiuo atvejuskaičius.html. Atidarykite HTML failą ir pamatysite geltonai paryškintas kodo dalis, kurios vis dar priklauso nuo „Python“. Galite spustelėti geltonas sritis, kad pamatytumėte pagrindinį „Cython“ sugeneruotą C kodą.